summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/README93
-rw-r--r--contrib/babel/library-of-babel.org584
-rw-r--r--contrib/lisp/htmlize.el1248
-rw-r--r--contrib/lisp/ob-eukleides.el98
-rw-r--r--contrib/lisp/ob-fomus.el (renamed from contrib/babel/langs/ob-fomus.el)7
-rw-r--r--contrib/lisp/ob-julia.el302
-rw-r--r--contrib/lisp/ob-mathomatic.el145
-rw-r--r--contrib/lisp/ob-oz.el (renamed from contrib/babel/langs/ob-oz.el)40
-rw-r--r--contrib/lisp/ob-tcl.el128
-rw-r--r--contrib/lisp/org-annotate-file.el2
-rw-r--r--contrib/lisp/org-bibtex-extras.el10
-rw-r--r--contrib/lisp/org-bookmark.el6
-rw-r--r--contrib/lisp/org-bullets.el122
-rw-r--r--contrib/lisp/org-checklist.el7
-rw-r--r--contrib/lisp/org-choose.el730
-rw-r--r--contrib/lisp/org-collector.el6
-rw-r--r--contrib/lisp/org-colview-xemacs.el1721
-rw-r--r--contrib/lisp/org-contacts.el562
-rw-r--r--contrib/lisp/org-contribdir.el6
-rw-r--r--contrib/lisp/org-depend.el24
-rw-r--r--contrib/lisp/org-drill.el756
-rw-r--r--contrib/lisp/org-e-ascii.el1807
-rw-r--r--contrib/lisp/org-e-beamer.el1069
-rw-r--r--contrib/lisp/org-e-html.el3044
-rw-r--r--contrib/lisp/org-e-latex.el2726
-rw-r--r--contrib/lisp/org-e-man.el1363
-rw-r--r--contrib/lisp/org-e-odt.el3762
-rw-r--r--contrib/lisp/org-e-publish.el1200
-rw-r--r--contrib/lisp/org-e-texinfo.el1844
-rw-r--r--contrib/lisp/org-elisp-symbol.el7
-rw-r--r--contrib/lisp/org-eval-light.el10
-rw-r--r--contrib/lisp/org-eval.el13
-rw-r--r--contrib/lisp/org-exp-bibtex.el148
-rw-r--r--contrib/lisp/org-expiry.el9
-rw-r--r--contrib/lisp/org-export-generic.el1504
-rw-r--r--contrib/lisp/org-export.el4518
-rwxr-xr-xcontrib/lisp/org-favtable.el1701
-rw-r--r--contrib/lisp/org-git-link.el18
-rw-r--r--contrib/lisp/org-interactive-query.el5
-rw-r--r--contrib/lisp/org-invoice.el12
-rw-r--r--contrib/lisp/org-jira.el7
-rw-r--r--contrib/lisp/org-learn.el6
-rw-r--r--contrib/lisp/org-mac-iCal.el25
-rw-r--r--contrib/lisp/org-mac-link-grabber.el7
-rw-r--r--contrib/lisp/org-mac-message.el217
-rw-r--r--contrib/lisp/org-mairix.el8
-rw-r--r--contrib/lisp/org-man.el21
-rw-r--r--contrib/lisp/org-md.el461
-rw-r--r--contrib/lisp/org-mew.el364
-rw-r--r--contrib/lisp/org-mime.el42
-rw-r--r--contrib/lisp/org-mtags.el10
-rw-r--r--contrib/lisp/org-notify.el63
-rw-r--r--contrib/lisp/org-notmuch.el6
-rw-r--r--contrib/lisp/org-panel.el21
-rw-r--r--contrib/lisp/org-registry.el7
-rw-r--r--contrib/lisp/org-screen.el10
-rw-r--r--contrib/lisp/org-secretary.el6
-rw-r--r--contrib/lisp/org-static-mathjax.el18
-rw-r--r--contrib/lisp/org-sudoku.el10
-rw-r--r--contrib/lisp/org-toc.el34
-rw-r--r--contrib/lisp/org-track.el33
-rw-r--r--contrib/lisp/org-velocity.el7
-rw-r--r--contrib/lisp/org-vm.el180
-rw-r--r--contrib/lisp/org-wikinodes.el53
-rw-r--r--contrib/lisp/org-wl.el311
-rw-r--r--contrib/lisp/org2rem.el651
-rw-r--r--contrib/lisp/orgtbl-sqlinsert.el10
-rw-r--r--contrib/lisp/ox-confluence.el191
-rw-r--r--contrib/lisp/ox-deck.el601
-rw-r--r--contrib/lisp/ox-freemind.el536
-rw-r--r--contrib/lisp/ox-groff.el (renamed from contrib/lisp/org-e-groff.el)1242
-rw-r--r--contrib/lisp/ox-koma-letter.el371
-rw-r--r--contrib/lisp/ox-rss.el410
-rw-r--r--contrib/lisp/ox-s5.el445
-rw-r--r--contrib/lisp/ox-taskjuggler.el904
-rw-r--r--contrib/scripts/StartOzServer.oz2
-rwxr-xr-xcontrib/scripts/dir2org.zsh2
-rw-r--r--contrib/scripts/ditaa.jarbin0 -> 186095 bytes
-rwxr-xr-xcontrib/scripts/org2hpda2
-rw-r--r--contrib/scripts/staticmathjax/application.ini2
-rw-r--r--contrib/scripts/x11idle.c28
81 files changed, 11563 insertions, 27118 deletions
diff --git a/contrib/README b/contrib/README
index 7f71ae9..3b9d9b7 100644
--- a/contrib/README
+++ b/contrib/README
@@ -1,34 +1,36 @@
This directory contains add-ons to Org-mode.
-These contributions are not part of GNU Emacs or of the official Org-mode
-package. But the git repository for Org-mode is glad to provide useful way
-to distribute and develop them as long as they are distributed under a free
-software license.
+These contributions are not part of GNU Emacs or of the official
+Org-mode package. But the git repository for Org-mode is glad to
+provide useful way to distribute and develop them as long as they
+are distributed under a free software license.
Please put your contribution in one of these directories:
-LISP (emacs-lisp code)
-======================
-htmlize.el --- Convert buffer text and decorations to HTML
-org2rem.el --- Convert org appointments into reminders
+LISP (Emacs Lisp)
+=================
+
+Org utils
+~~~~~~~~~
org-annotate-file.el --- Annotate a file with org syntax
org-bibtex-extras.el --- Extras for working with org-bibtex entries
org-bookmark.el --- Links to bookmarks
+org-bullets.el --- Show bullets in org-mode as UTF-8 characters
org-checklist.el --- org functions for checklist handling
org-choose.el --- Use TODO keywords to mark decision states
org-collector.el --- Collect properties into tables
-org-contacts --- Contacts management
+org-colview-xemacs.el --- Column View in Org-mode, XEmacs-specific version
+org-contacts.el --- Contacts management
org-contribdir.el --- Dummy file to mark the org contrib Lisp directory
org-depend.el --- TODO dependencies for Org-mode
org-drill.el --- Self-testing with org-learn
org-element.el --- Parser and applications for Org syntax
org-elisp-symbol.el --- Org links to emacs-lisp symbols
-org-eval.el --- The <lisp> tag, adapted from Muse
org-eval-light.el --- Evaluate in-buffer code on demand
-org-exp-bibtex.el --- Export citations to LaTeX and HTML
-org-expiry.el --- Expiry mechanism for Org entries
-org-export.el --- Generic Export Engine For Org
+org-eval.el --- The <lisp> tag, adapted from Muse
+org-expiry.el --- Expiry mechanism for Org entries
org-export-generic.el --- Export framework for configurable backends
+org-favtable.el --- Lookup table of favorite references and links
org-git-link.el --- Provide org links to specific file version
org-interactive-query.el --- Interactive modification of tags query
org-invoice.el --- Help manage client invoices in OrgMode
@@ -36,8 +38,10 @@ org-jira.el --- Add a jira:ticket protocol to Org
org-learn.el --- SuperMemo's incremental learning algorithm
org-mac-iCal.el --- Imports events from iCal.app to the Emacs diary
org-mac-link-grabber.el --- Grab links and URLs from various Mac applications
+org-mac-message.el --- Links to Apple Mail.app messages from within Org-mode
org-mairix.el --- Hook mairix search into Org for different MUAs
org-man.el --- Support for links to manpages in Org-mode
+org-mew.el --- Support for links to Mew messages
org-mime.el --- org html export for text/html MIME emails
org-mtags.el --- Support for some Muse-like tags in Org-mode
org-notify.el --- Notifications for Org-mode
@@ -48,49 +52,48 @@ org-screen.el --- Visit screen sessions through Org-mode links
org-secretary.el --- Team management with org-mode
org-static-mathjax.el --- Muse-like tags in Org-mode
org-sudoku.el --- Create and solve SUDOKU puzzles in Org tables
-orgtbl-sqlinsert.el --- Convert Org-mode tables to SQL insertions
org-toc.el --- Table of contents for Org-mode buffer
org-track.el --- Keep up with Org development
org-velocity.el --- something like Notational Velocity for Org
+org-vm.el --- Support for links to VM messages
+org-w3m.el --- Support link/copy/paste from w3m to Org-mode
org-wikinodes.el --- CamelCase wiki-like links for Org
+org-wl.el --- Support for links to Wanderlust messages
+orgtbl-sqlinsert.el --- Convert Org-mode tables to SQL insertions
+Org exporters
+~~~~~~~~~~~~~
+ox-confluence.el --- Confluence Wiki exporter
+ox-deck.el --- deck.js presentations exporter
+ox-groff.el --- Groff exporter
+ox-koma-letter.el --- KOMA Scrlttr2 exporter
+ox-rss.el --- RSS 2.0 exporter
+ox-s5.el --- S5 presentations exporter
+ox-taskjuggler.el --- TaskJuggler exporter
-EXPORT ENGINE AND BACKENDS (emacs-lisp code)
-============================================
-
-org-export.el --- the new export engine
-org-e-latex.el --- LaTeX export backend
-org-e-ascii.el --- ASCII export backend
-org-e-beamer.el --- Beamer export backend
-org-e-groff.el --- Groff export backend
-org-e-html.el --- HTML export backend
-org-e-man.el --- man pages export backend
-org-e-odt.el --- ODT export backend
-org-e-texinfo.el --- TeXinfo export backend
-org-md.el --- MarkDown export backend
-
-
-BABEL
-=====
-library-of-babel.org --- Documentation for the library of babel
-langs/ob-fomus.el --- Org-babel functions for fomus evaluation
-langs/ob-oz.el --- Org-babel functions for Oz evaluation
-
+Org Babel languages
+~~~~~~~~~~~~~~~~~~~
+ob-eukleides.el --- Org-babel functions for eukleides evaluation
+ob-fomus.el --- Org-babel functions for fomus evaluation
+ob-julia.el --- Org-babel functions for julia evaluation
+ob-mathomatic.el --- Org-babel functions for mathomatic evaluation
+ob-oz.el --- Org-babel functions for Oz evaluation
+ob-tcl.el --- Org-babel functions for tcl evaluation
-ODT (OpenDocumentText)
-======================
-README.org --- Legacy documentation for Org ODT exporter
+External libraries
+~~~~~~~~~~~~~~~~~~
+htmlize.el --- Convert buffer text and decorations to HTML
SCRIPTS (shell, bash, etc.)
===========================
-
-dir2org.zsh --- Org compatible fs structure output
-ditaa.jar --- ASCII to PNG converter by Stathis Sideris, GPL
-org2hpda --- Generate hipster pda style printouts from Org-mode
-org-docco.org --- docco side-by-side annotated code export to HTML
-StartOzServer.oz --- implements the Oz-side of the Org-babel Oz interface
-staticmathjax --- XULRunner application to process MathJax statically
+StartOzServer.oz --- implements the Oz-side of the Org-babel Oz interface
+dir2org.zsh --- Org compatible fs structure output
+ditaa.jar --- ASCII to PNG converter by Stathis Sideris, GPL
+org-docco.org --- docco side-by-side annotated code export to HTML
+org2hpda --- Generate hipster pda style printouts from Org-mode
+staticmathjax --- XULRunner application to process MathJax statically
+x11idle.c --- get the idle time of your X session
This directory also contains supporting files for the following
packages: ob-oz.el, org-docco.org, and org-static-mathjax.el.
diff --git a/contrib/babel/library-of-babel.org b/contrib/babel/library-of-babel.org
deleted file mode 100644
index 0098e72..0000000
--- a/contrib/babel/library-of-babel.org
+++ /dev/null
@@ -1,584 +0,0 @@
-#+title: The Library of Babel
-#+author: Org-mode People
-#+STARTUP: hideblocks
-
-* Introduction
-
-The Library of Babel is an extensible collection of ready-made and
-easily-shortcut-callable source-code blocks for handling common tasks.
-Org-babel comes pre-populated with the source-code blocks located in
-this file. It is possible to add source-code blocks from any org-mode
-file to the library by calling =(org-babel-lob-ingest
-"path/to/file.org")=.
-
-This file is included in worg mainly less for viewing through the web
-interface, and more for contribution through the worg git repository.
-If you have code snippets that you think others may find useful please
-add them to this file and [[file:~/src/worg/worg-git.org::contribute-to-worg][contribute them]] to worg.
-
-The raw Org-mode text of this file can be downloaded at
-[[repofile:contrib/babel/library-of-babel.org][library-of-babel.org]]
-
-* Simple
-
-A collection of simple utility functions:
-
-#+name: echo
-#+begin_src emacs-lisp :var input="echo'd"
- input
-#+end_src
-
-* File I/O
-
-** Reading and writing files
-
-Read the contents of the file at =file=. The =:results vector= and
-=:results scalar= header arguments can be used to read the contents of
-file as either a table or a string.
-
-#+name: read
-#+begin_src emacs-lisp :var file="" :var format=""
- (if (string= format "csv")
- (with-temp-buffer
- (org-table-import (expand-file-name file) nil)
- (org-table-to-lisp))
- (with-temp-buffer
- (insert-file-contents (expand-file-name file))
- (buffer-string)))
-#+end_src
-
-Write =data= to a file at =file=. If =data= is a list, then write it
-as a table in traditional Org-mode table syntax.
-
-#+name: write
-#+begin_src emacs-lisp :var data="" :var file="" :var ext='()
- (flet ((echo (r) (if (stringp r) r (format "%S" r))))
- (with-temp-file file
- (case (and (listp data)
- (or ext (intern (file-name-extension file))))
- ('tsv (insert (orgtbl-to-tsv data '(:fmt echo))))
- ('csv (insert (orgtbl-to-csv data '(:fmt echo))))
- (t (org-babel-insert-result data)))))
- nil
-#+end_src
-
-** Remote files
-
-*** json
-
-Read local or remote file in [[http://www.json.org/][json]] format into emacs-lisp objects.
-
-#+name: json
-#+begin_src emacs-lisp :var file='() :var url='()
- (require 'json)
- (cond
- (file
- (with-temp-filebuffer file
- (goto-char (point-min))
- (json-read)))
- (url
- (require 'w3m)
- (with-temp-buffer
- (w3m-retrieve url)
- (goto-char (point-min))
- (json-read))))
-#+end_src
-
-*** Google docs
-
-The following code blocks make use of the [[http://code.google.com/p/googlecl/][googlecl]] Google command line
-tool. This tool provides functionality for accessing Google services
-from the command line, and the following code blocks use /googlecl/
-for reading from and writing to Google docs with Org-mode code blocks.
-
-**** Read a document from Google docs
-
-The =google= command seems to be throwing "Moved Temporarily" errors
-when trying to download textual documents, but this is working fine
-for spreadsheets.
-
-#+name: gdoc-read
-#+begin_src emacs-lisp :var title="example" :var format="csv"
- (let* ((file (concat title "." format))
- (cmd (format "google docs get --format %S --title %S" format title)))
- (message cmd) (message (shell-command-to-string cmd))
- (prog1 (if (string= format "csv")
- (with-temp-buffer
- (org-table-import (shell-quote-argument file) '(4))
- (org-table-to-lisp))
- (with-temp-buffer
- (insert-file-contents (shell-quote-argument file))
- (buffer-string)))
- (delete-file file)))
-#+end_src
-
-For example, a line like the following can be used to read the
-contents of a spreadsheet named =num-cells= into a table.
-: #+call: gdoc-read(title="num-cells"")
-
-A line like the following can be used to read the contents of a
-document as a string.
-
-: #+call: gdoc-read(title="loremi", :format "txt")
-
-**** Write a document to a Google docs
-
-Write =data= to a google document named =title=. If =data= is tabular
-it will be saved to a spreadsheet, otherwise it will be saved as a
-normal document.
-
-#+name: gdoc-write
-#+begin_src emacs-lisp :var title="babel-upload" :var data=fibs(n=10) :results silent
- (let* ((format (if (listp data) "csv" "txt"))
- (tmp-file (make-temp-file "org-babel-google-doc" nil (concat "." format)))
- (cmd (format "google docs upload --title %S %S" title tmp-file)))
- (with-temp-file tmp-file
- (insert
- (if (listp data)
- (orgtbl-to-csv
- data '(:fmt (lambda (el) (if (stringp el) el (format "%S" el)))))
- (if (stringp data) data (format "%S" data)))))
- (message cmd)
- (prog1 (shell-command-to-string cmd) (delete-file tmp-file)))
-#+end_src
-
-example usage
-: #+name: fibs
-: #+begin_src emacs-lisp :var n=8
-: (flet ((fib (m) (if (< m 2) 1 (+ (fib (- m 1)) (fib (- m 2))))))
-: (mapcar (lambda (el) (list el (fib el))) (number-sequence 0 (- n 1))))
-: #+end_src
-:
-: #+call: gdoc-write(title="fibs", data=fibs(n=10))
-
-* Plotting code
-
-** R
-
-Plot column 2 (y axis) against column 1 (x axis). Columns 3 and
-beyond, if present, are ignored.
-
-#+name: R-plot
-#+begin_src R :var data=R-plot-example-data
-plot(data)
-#+end_src
-
-#+tblname: R-plot-example-data
-| 1 | 2 |
-| 2 | 4 |
-| 3 | 9 |
-| 4 | 16 |
-| 5 | 25 |
-
-#+call: R-plot(data=R-plot-example-data)
-
-#+resname: R-plot(data=R-plot-example-data)
-: nil
-
-** Gnuplot
-
-* Org reference
-
-** Headline references
-
-#+name: headline
-#+begin_src emacs-lisp :var headline=top :var file='()
- (save-excursion
- (when file (get-file-buffer file))
- (org-open-link-from-string (org-make-link-string headline))
- (save-restriction
- (org-narrow-to-subtree)
- (buffer-string)))
-#+end_src
-
-#+call: headline(headline="headline references")
-
-* Tables
-
-** LaTeX Table Export
-
-*** booktabs
-
-This source block can be used to wrap a table in the latex =booktabs=
-environment. The source block adds a =toprule= and =bottomrule= (so
-don't use =hline= at the top or bottom of the table). The =hline=
-after the header is replaced with a =midrule=.
-
-Note that this function bypasses the Org-mode LaTeX exporter and calls
-=orgtbl-to-generic= to create the output table. This means that the
-entries in the table are not translated from Org-mode to LaTeX.
-
-It takes the following arguments -- all but the first two are
-optional.
-
-| arg | description |
-|-------+--------------------------------------------|
-| table | a reference to the table |
-| align | alignment string |
-| env | optional environment, default to "tabular" |
-| width | optional width specification string |
-
-#+name: booktabs
-#+begin_src emacs-lisp :var table='((:head) hline (:body)) :var align='() :var env="tabular" :var width='() :noweb yes :results latex
- (flet ((to-tab (tab)
- (orgtbl-to-generic
- (mapcar (lambda (lis)
- (if (listp lis)
- (mapcar (lambda (el)
- (if (stringp el)
- el
- (format "%S" el))) lis)
- lis)) tab)
- (list :lend " \\\\" :sep " & " :hline "\\hline"))))
- (org-fill-template
- "
- \\begin{%env}%width%align
- \\toprule
- %table
- \\bottomrule
- \\end{%env}\n"
- (list
- (cons "env" (or env "table"))
- (cons "width" (if width (format "{%s}" width) ""))
- (cons "align" (if align (format "{%s}" align) ""))
- (cons "table"
- ;; only use \midrule if it looks like there are column headers
- (if (equal 'hline (second table))
- (concat (to-tab (list (first table)))
- "\n\\midrule\n"
- (to-tab (cddr table)))
- (to-tab table))))))
-#+end_src
-
-*** longtable
-
-This block can be used to wrap a table in the latex =longtable=
-environment, it takes the following arguments -- all but the first two
-are optional.
-
-| arg | description |
-|-----------+-------------------------------------------------------------|
-| table | a reference to the table |
-| align | optional alignment string |
-| width | optional width specification string |
-| hline | the string to use as hline separator, defaults to "\\hline" |
-| head | optional "head" string |
-| firsthead | optional "firsthead" string |
-| foot | optional "foot" string |
-| lastfoot | optional "lastfoot" string |
-
-#+name: longtable
-#+begin_src emacs-lisp :var table='((:table)) :var align='() :var width='() :var hline="\\hline" :var firsthead='() :var head='() :var foot='() :var lastfoot='() :noweb yes :results latex
- (org-fill-template
- "
- \\begin{longtable}%width%align
- %firsthead
- %head
- %foot
- %lastfoot
-
- %table
- \\end{longtable}\n"
- (list
- (cons "width" (if width (format "{%s}" width) ""))
- (cons "align" (if align (format "{%s}" align) ""))
- (cons "firsthead" (if firsthead (concat firsthead "\n\\endfirsthead\n") ""))
- (cons "head" (if head (concat head "\n\\endhead\n") ""))
- (cons "foot" (if foot (concat foot "\n\\endfoot\n") ""))
- (cons "lastfoot" (if lastfoot (concat lastfoot "\n\\endlastfoot\n") ""))
- (cons "table" (orgtbl-to-generic
- (mapcar (lambda (lis)
- (if (listp lis)
- (mapcar (lambda (el)
- (if (stringp el)
- el
- (format "%S" el))) lis)
- lis)) table)
- (list :lend " \\\\" :sep " & " :hline hline)))))
-#+end_src
-
-*** booktabs-notes
-
-This source block builds on [[booktabs]]. It accepts two additional
-arguments, both of which are optional.
-
-#+tblname: arguments
-| arg | description |
-|--------+------------------------------------------------------|
-| notes | an org-mode table with footnotes |
-| lspace | if non-nil, insert =addlinespace= after =bottomrule= |
-
-An example footnote to the =arguments= table specifies the column
-span. Note the use of LaTeX, rather than Org-mode, markup.
-
-#+tblname: arguments-notes
-| \multicolumn{2}{l}{This is a footnote to the \emph{arguments} table.} |
-
-#+name: booktabs-notes
-#+begin_src emacs-lisp :var table='((:head) hline (:body)) :var notes='() :var align='() :var env="tabular" :var width='() :var lspace='() :noweb yes :results latex
- (flet ((to-tab (tab)
- (orgtbl-to-generic
- (mapcar (lambda (lis)
- (if (listp lis)
- (mapcar (lambda (el)
- (if (stringp el)
- el
- (format "%S" el))) lis)
- lis)) tab)
- (list :lend " \\\\" :sep " & " :hline "\\hline"))))
- (org-fill-template
- "
- \\begin{%env}%width%align
- \\toprule
- %table
- \\bottomrule%spacer
- %notes
- \\end{%env}\n"
- (list
- (cons "env" (or env "table"))
- (cons "width" (if width (format "{%s}" width) ""))
- (cons "align" (if align (format "{%s}" align) ""))
- (cons "spacer" (if lspace "\\addlinespace" ""))
- (cons "table"
- ;; only use \midrule if it looks like there are column headers
- (if (equal 'hline (second table))
- (concat (to-tab (list (first table)))
- "\n\\midrule\n"
- (to-tab (cddr table)))
- (to-tab table)))
- (cons "notes" (if notes (to-tab notes) ""))
- )))
-#+end_src
-
-** Elegant lisp for transposing a matrix
-
-#+tblname: transpose-example
-| 1 | 2 | 3 |
-| 4 | 5 | 6 |
-
-#+name: transpose
-#+begin_src emacs-lisp :var table=transpose-example
- (apply #'mapcar* #'list table)
-#+end_src
-
-#+resname:
-| 1 | 4 |
-| 2 | 5 |
-| 3 | 6 |
-
-** Convert every element of a table to a string
-
-#+tblname: hetero-table
-| 1 | 2 | 3 |
-| a | b | c |
-
-#+name: all-to-string
-#+begin_src emacs-lisp :var tbl='()
- (defun all-to-string (tbl)
- (if (listp tbl)
- (mapcar #'all-to-string tbl)
- (if (stringp tbl)
- tbl
- (format "%s" tbl))))
- (all-to-string tbl)
-#+end_src
-
-#+begin_src emacs-lisp :var tbl=hetero-table
- (mapcar (lambda (row) (mapcar (lambda (cell) (stringp cell)) row)) tbl)
-#+end_src
-
-#+name:
-| nil | nil | nil |
-| t | t | t |
-
-#+begin_src emacs-lisp :var tbl=all-to-string(hetero-table)
- (mapcar (lambda (row) (mapcar (lambda (cell) (stringp cell)) row)) tbl)
-#+end_src
-
-#+name:
-| t | t | t |
-| t | t | t |
-
-* Misc
-
-** File-specific Version Control logging
- :PROPERTIES:
- :AUTHOR: Luke Crook
- :END:
-
-This function will attempt to retrieve the entire commit log for the
-file associated with the current buffer and insert this log into the
-export. The function uses the Emacs VC commands to interface to the
-local version control system, but has only been tested to work with
-Git. 'limit' is currently unsupported.
-
-#+name: vc-log
-#+headers: :var limit=-1
-#+headers: :var buf=(buffer-name (current-buffer))
-#+begin_src emacs-lisp
- ;; Most of this code is copied from vc.el vc-print-log
- (require 'vc)
- (when (vc-find-backend-function
- (vc-backend (buffer-file-name (get-buffer buf))) 'print-log)
- (let ((limit -1)
- (vc-fileset nil)
- (backend nil)
- (files nil))
- (with-current-buffer (get-buffer buf)
- (setq vc-fileset (vc-deduce-fileset t)) ; FIXME: Why t? --Stef
- (setq backend (car vc-fileset))
- (setq files (cadr vc-fileset)))
- (with-temp-buffer
- (let ((status (vc-call-backend
- backend 'print-log files (current-buffer))))
- (when (and (processp status) ; Make sure status is a process
- (= 0 (process-exit-status status))) ; which has not terminated
- (while (not (eq 'exit (process-status status)))
- (sit-for 1 t)))
- (buffer-string)))))
-#+end_src
-
-** Trivial python code blocks
-
-#+name: python-identity
-#+begin_src python :var a=1
-a
-#+end_src
-
-#+name: python-add
-#+begin_src python :var a=1 :var b=2
-a + b
-#+end_src
-
-** Arithmetic
-
-#+name: lob-add
-#+begin_src emacs-lisp :var a=0 :var b=0
- (+ a b)
-#+end_src
-
-#+name: lob-minus
-#+begin_src emacs-lisp :var a=0 :var b=0
- (- a b)
-#+end_src
-
-#+name: lob-times
-#+begin_src emacs-lisp :var a=0 :var b=0
- (* a b)
-#+end_src
-
-#+name: lob-div
-#+begin_src emacs-lisp :var a=0 :var b=0
- (/ a b)
-#+end_src
-
-* GANTT Charts
-
-The =elispgantt= source block was sent to the mailing list by Eric
-Fraga. It was modified slightly by Tom Dye.
-
-#+name: elispgantt
-#+begin_src emacs-lisp :var table=gantttest
- (let ((dates "")
- (entries (nthcdr 2 table))
- (milestones "")
- (nmilestones 0)
- (ntasks 0)
- (projecttime 0)
- (tasks "")
- (xlength 1))
- (message "Initial: %s\n" table)
- (message "Entries: %s\n" entries)
- (while entries
- (let ((entry (first entries)))
- (if (listp entry)
- (let ((id (first entry))
- (type (nth 1 entry))
- (label (nth 2 entry))
- (task (nth 3 entry))
- (dependencies (nth 4 entry))
- (start (nth 5 entry))
- (duration (nth 6 entry))
- (end (nth 7 entry))
- (alignment (nth 8 entry)))
- (if (> start projecttime) (setq projecttime start))
- (if (string= type "task")
- (let ((end (+ start duration))
- (textposition (+ start (/ duration 2)))
- (flush ""))
- (if (string= alignment "left")
- (progn
- (setq textposition start)
- (setq flush "[left]"))
- (if (string= alignment "right")
- (progn
- (setq textposition end)
- (setq flush "[right]"))))
- (setq tasks
- (format "%s \\gantttask{%s}{%s}{%d}{%d}{%d}{%s}\n"
- tasks label task start end textposition flush))
- (setq ntasks (+ 1 ntasks))
- (if (> end projecttime)
- (setq projecttime end)))
- (if (string= type "milestone")
- (progn
- (setq milestones
- (format
- "%s \\ganttmilestone{$\\begin{array}{c}\\mbox{%s}\\\\ \\mbox{%s}\\end{array}$}{%d}\n"
- milestones label task start))
- (setq nmilestones (+ 1 nmilestones)))
- (if (string= type "date")
- (setq dates (format "%s \\ganttdateline{%s}{%d}\n"
- dates label start))
- (message "Ignoring entry with type %s\n" type)))))
- (message "Ignoring non-list entry %s\n" entry)) ; end if list entry
- (setq entries (cdr entries)))) ; end while entries left
- (format "\\pgfdeclarelayer{background}
- \\pgfdeclarelayer{foreground}
- \\pgfsetlayers{background,foreground}
- \\renewcommand{\\ganttprojecttime}{%d}
- \\renewcommand{\\ganttntasks}{%d}
- \\noindent
- \\begin{tikzpicture}[y=-0.75cm,x=0.75\\textwidth]
- \\begin{pgfonlayer}{background}
- \\draw[very thin, red!10!white] (0,1+\\ganttntasks) grid [ystep=0.75cm,xstep=1/\\ganttprojecttime] (1,0);
- \\draw[\\ganttdatelinecolour] (0,0) -- (1,0);
- \\draw[\\ganttdatelinecolour] (0,1+\\ganttntasks) -- (1,1+\\ganttntasks);
- \\end{pgfonlayer}
- %s
- %s
- %s
- \\end{tikzpicture}" projecttime ntasks tasks milestones dates))
-#+end_src
-
-* Available languages
- :PROPERTIES:
- :AUTHOR: Bastien
- :END:
-
-** From Org's core
-
-| Language | Identifier | Language | Identifier |
-|------------+------------+----------------+------------|
-| Asymptote | asymptote | Awk | awk |
-| Emacs Calc | calc | C | C |
-| C++ | C++ | Clojure | clojure |
-| CSS | css | ditaa | ditaa |
-| Graphviz | dot | Emacs Lisp | emacs-lisp |
-| gnuplot | gnuplot | Haskell | haskell |
-| Javascript | js | LaTeX | latex |
-| Ledger | ledger | Lisp | lisp |
-| Lilypond | lilypond | MATLAB | matlab |
-| Mscgen | mscgen | Objective Caml | ocaml |
-| Octave | octave | Org-mode | org |
-| | | Perl | perl |
-| Plantuml | plantuml | Python | python |
-| R | R | Ruby | ruby |
-| Sass | sass | Scheme | scheme |
-| GNU Screen | screen | shell | sh |
-| SQL | sql | SQLite | sqlite |
-
-** From Org's contrib/babel/langs
-
-- ob-oz.el, by Torsten Anders and Eric Schulte
-- ob-fomus.el, by Torsten Anders
diff --git a/contrib/lisp/htmlize.el b/contrib/lisp/htmlize.el
index 516fb1d..c03d605 100644
--- a/contrib/lisp/htmlize.el
+++ b/contrib/lisp/htmlize.el
@@ -1,9 +1,12 @@
-;; htmlize.el -- Convert buffer text and decorations to HTML.
+;;; htmlize.el --- Convert buffer text and decorations to HTML.
-;; Copyright (C) 1997-2012 Hrvoje Niksic
+;; Copyright (C) 1997-2013 Hrvoje Niksic
;; Author: Hrvoje Niksic <hniksic@xemacs.org>
;; Keywords: hypermedia, extensions
+;; Version: 1.43
+
+;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -26,7 +29,7 @@
;; decorations to HTML. Mail to <hniksic@xemacs.org> to discuss
;; features and additions. All suggestions are more than welcome.
-;; To use this, just switch to the buffer you want HTML-ized and type
+;; To use it, just switch to the buffer you want HTML-ized and type
;; `M-x htmlize-buffer'. You will be switched to a new buffer that
;; contains the resulting HTML code. You can edit and inspect this
;; buffer, or you can just save it with C-x C-w. `M-x htmlize-file'
@@ -44,37 +47,43 @@
;; produced HTML is valid under the 4.01 strict DTD, as confirmed by
;; the W3C validator. `inline-css' is like `css', except the CSS is
;; put directly in the STYLE attribute of the SPAN element, making it
-;; possible to paste the generated HTML to other documents. In `font'
-;; mode, htmlize uses <font color="...">...</font> to colorize HTML,
-;; which is not standard-compliant, but works better in older
-;; browsers. `css' mode is the default.
+;; possible to paste the generated HTML into existing HTML documents.
+;; In `font' mode, htmlize uses <font color="...">...</font> to
+;; colorize HTML, which is not standard-compliant, but works better in
+;; older browsers. `css' mode is the default.
;; You can also use htmlize from your Emacs Lisp code. When called
;; non-interactively, `htmlize-buffer' and `htmlize-region' will
;; return the resulting HTML buffer, but will not change current
-;; buffer or move the point.
-
-;; I tried to make the package elisp-compatible with multiple Emacsen,
-;; specifically aiming for XEmacs 19.14+ and GNU Emacs 19.34+. Please
-;; let me know if it doesn't work on some of those, and I'll try to
-;; fix it. I relied heavily on the presence of CL extensions,
-;; especially for cross-emacs compatibility; please don't try to
-;; remove that particular dependency. When byte-compiling under GNU
-;; Emacs, you're likely to get some warnings; just ignore them.
-
-;; The latest version should be available at:
+;; buffer or move the point. htmlize will do its best to work on
+;; non-windowing Emacs sessions but the result will be limited to
+;; colors supported by the terminal.
+
+;; htmlize aims for compatibility with Emacsen version 21 and later.
+;; Please let me know if it doesn't work on the version of XEmacs or
+;; GNU Emacs that you are using. The package relies on the presence
+;; of CL extensions, especially for cross-emacs compatibility; please
+;; don't try to remove that dependency. I see no practical problems
+;; with using the full power of the CL extensions, except that one
+;; might learn to like them too much.
+
+;; The latest version is available as a git repository at:
+;;
+;; <http://fly.srk.fer.hr/~hniksic/emacs/htmlize.git>
;;
-;; <http://fly.srk.fer.hr/~hniksic/emacs/htmlize.el>
+;; The snapshot of the latest release can be obtained at:
+;;
+;; <http://fly.srk.fer.hr/~hniksic/emacs/htmlize.el.cgi>
;;
;; You can find a sample of htmlize's output (possibly generated with
;; an older version) at:
;;
;; <http://fly.srk.fer.hr/~hniksic/emacs/htmlize.el.html>
-;; Thanks go to the multitudes of people who have sent reports and
-;; contributed comments, suggestions, and fixes. They include Ron
-;; Gut, Bob Weiner, Toni Drabik, Peter Breton, Thomas Vogels, Juri
-;; Linkov, Maciek Pasternacki, and many others.
+;; Thanks go to the many people who have sent reports and contributed
+;; comments, suggestions, and fixes. They include Ron Gut, Bob
+;; Weiner, Toni Drabik, Peter Breton, Ville Skytta, Thomas Vogels,
+;; Juri Linkov, Maciek Pasternacki, and many others.
;; User quotes: "You sir, are a sick, sick, _sick_ person. :)"
;; -- Bill Perry, author of Emacs/W3
@@ -84,48 +93,27 @@
(require 'cl)
(eval-when-compile
+ (defvar unresolved)
(if (string-match "XEmacs" emacs-version)
(byte-compiler-options
(warnings (- unresolved))))
(defvar font-lock-auto-fontify)
(defvar font-lock-support-mode)
- (defvar global-font-lock-mode)
- (when (and (eq emacs-major-version 19)
- (not (string-match "XEmacs" emacs-version)))
- ;; Older versions of GNU Emacs fail to autoload cl-extra even when
- ;; `cl' is loaded.
- (load "cl-extra")))
-
-(defconst htmlize-version "1.36")
-
-;; Incantations to make custom stuff work without customize, e.g. on
-;; XEmacs 19.14 or GNU Emacs 19.34.
-(eval-and-compile
- (condition-case ()
- (require 'custom)
- (error nil))
- (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
- nil ; we've got what we needed
- ;; No custom or obsolete custom, define surrogates. Define all
- ;; three macros, so we don't hose another library that expects
- ;; e.g. `defface' to work after (fboundp 'defcustom) succeeds.
- (defmacro defgroup (&rest ignored) nil)
- (defmacro defcustom (var value doc &rest ignored)
- `(defvar ,var ,value ,doc))
- (defmacro defface (face value doc &rest stuff)
- `(make-face ,face))))
+ (defvar global-font-lock-mode))
+
+(defconst htmlize-version "1.43")
(defgroup htmlize nil
"Convert buffer text and faces to HTML."
:group 'hypermedia)
(defcustom htmlize-head-tags ""
- "*Additional tags to insert within HEAD of the generated document."
+ "Additional tags to insert within HEAD of the generated document."
:type 'string
:group 'htmlize)
(defcustom htmlize-output-type 'css
- "*Output type of generated HTML, one of `css', `inline-css', or `font'.
+ "Output type of generated HTML, one of `css', `inline-css', or `font'.
When set to `css' (the default), htmlize will generate a style sheet
with description of faces, and use it in the HTML document, specifying
the faces in the actual text with <span class=\"FACE\">.
@@ -145,11 +133,47 @@ sheet to carry around)."
:type '(choice (const css) (const inline-css) (const font))
:group 'htmlize)
+(defcustom htmlize-use-images t
+ "Whether htmlize generates `img' for images attached to buffer contents."
+ :type 'boolean
+ :group 'htmlize)
+
+(defcustom htmlize-force-inline-images nil
+ "Non-nil means generate all images inline using data URLs.
+Normally htmlize converts image descriptors with :file properties to
+relative URIs, and those with :data properties to data URIs. With this
+flag set, the images specified as a file name are loaded into memory and
+embedded in the HTML as data URIs."
+ :type 'boolean
+ :group 'htmlize)
+
+(defcustom htmlize-max-alt-text 100
+ "Maximum size of text to use as ALT text in images.
+
+Normally when htmlize encounters text covered by the `display' property
+that specifies an image, it generates an `alt' attribute containing the
+original text. If the text is larger than `htmlize-max-alt-text' characters,
+this will not be done.")
+
+(defcustom htmlize-transform-image 'htmlize-default-transform-image
+ "Function called to modify the image descriptor.
+
+The function is called with the image descriptor found in the buffer and
+the text the image is supposed to replace. It should return a (possibly
+different) image descriptor property list or a replacement string to use
+instead of of the original buffer text.
+
+Returning nil is the same as returning the original text."
+ :type 'boolean
+ :group 'htmlize)
+
(defcustom htmlize-generate-hyperlinks t
- "*Non-nil means generate the hyperlinks for URLs and mail addresses.
+ "Non-nil means auto-generate the links from URLs and mail addresses in buffer.
+
This is on by default; set it to nil if you don't want htmlize to
-insert hyperlinks in the resulting HTML. (In which case you can still
-do your own hyperlinkification from htmlize-after-hook.)"
+autogenerate such links. Note that this option only turns off automatic
+search for contents that looks like URLs and converting them to links.
+It has no effect on whether htmlize respects the `htmlize-link' property."
:type 'boolean
:group 'htmlize)
@@ -164,12 +188,12 @@ do your own hyperlinkification from htmlize-after-hook.)"
text-decoration: underline;
}
"
- "*The CSS style used for hyperlinks when in CSS mode."
+ "The CSS style used for hyperlinks when in CSS mode."
:type 'string
:group 'htmlize)
(defcustom htmlize-replace-form-feeds t
- "*Non-nil means replace form feeds in source code with HTML separators.
+ "Non-nil means replace form feeds in source code with HTML separators.
Form feeds are the ^L characters at line beginnings that are sometimes
used to separate sections of source code. If this variable is set to
`t', form feed characters are replaced with the <hr> separator. If this
@@ -185,7 +209,7 @@ htmlize-after-hook."
:group 'htmlize)
(defcustom htmlize-html-charset nil
- "*The charset declared by the resulting HTML documents.
+ "The charset declared by the resulting HTML documents.
When non-nil, causes htmlize to insert the following in the HEAD section
of the generated HTML:
@@ -201,16 +225,16 @@ submitted HTML documents to declare a charset. So if you care about
validation, you can use this to prevent the validator from bitching.
Needless to say, if you set this, you should actually make sure that
-the buffer is in the encoding you're claiming it is in. (Under Mule
-that is done by ensuring the correct \"file coding system\" for the
-buffer.) If you don't understand what that means, this option is
-probably not for you."
+the buffer is in the encoding you're claiming it is in. (This is
+normally achieved by using the correct file coding system for the
+buffer.) If you don't understand what that means, you should probably
+leave this option in its default setting."
:type '(choice (const :tag "Unset" nil)
string)
:group 'htmlize)
-(defcustom htmlize-convert-nonascii-to-entities (featurep 'mule)
- "*Whether non-ASCII characters should be converted to HTML entities.
+(defcustom htmlize-convert-nonascii-to-entities t
+ "Whether non-ASCII characters should be converted to HTML entities.
When this is non-nil, characters with codes in the 128-255 range will be
considered Latin 1 and rewritten as \"&#CODE;\". Characters with codes
@@ -231,21 +255,13 @@ which has nothing to do with the charset the page is in. For example,
specified by the META tag or the charset sent by the HTTP server. In
other words, \"&#169;\" is exactly equivalent to \"&copy;\".
-By default, entity conversion is turned on for Mule-enabled Emacsen and
-turned off otherwise. This is because Mule knows the charset of
-non-ASCII characters in the buffer. A non-Mule Emacs cannot tell
-whether a character with code 0xA9 represents Latin 1 copyright symbol,
-Latin 2 \"S with caron\", or something else altogether. Setting this to
-t without Mule means asserting that 128-255 characters always mean Latin
-1.
-
For most people htmlize will work fine with this option left at the
default setting; don't change it unless you know what you're doing."
:type 'sexp
:group 'htmlize)
(defcustom htmlize-ignore-face-size 'absolute
- "*Whether face size should be ignored when generating HTML.
+ "Whether face size should be ignored when generating HTML.
If this is nil, face sizes are used. If set to t, sizes are ignored
If set to `absolute', only absolute size specifications are ignored.
Please note that font sizes only work with CSS-based output types."
@@ -255,7 +271,7 @@ Please note that font sizes only work with CSS-based output types."
:group 'htmlize)
(defcustom htmlize-css-name-prefix ""
- "*The prefix used for CSS names.
+ "The prefix used for CSS names.
The CSS names that htmlize generates from face names are often too
generic for CSS files; for example, `font-lock-type-face' is transformed
to `type'. Use this variable to add a prefix to the generated names.
@@ -264,7 +280,7 @@ The string \"htmlize-\" is an example of a reasonable prefix."
:group 'htmlize)
(defcustom htmlize-use-rgb-txt t
- "*Whether `rgb.txt' should be used to convert color names to RGB.
+ "Whether `rgb.txt' should be used to convert color names to RGB.
This conversion means determining, for instance, that the color
\"IndianRed\" corresponds to the (205, 92, 92) RGB triple. `rgb.txt'
@@ -273,7 +289,7 @@ triples. When this variable is non-nil, `htmlize' uses `rgb.txt' to
look up color names.
If this variable is nil, htmlize queries Emacs for RGB components of
-colors using `color-instance-rgb-components' and `x-color-values'.
+colors using `color-instance-rgb-components' and `color-values'.
This can yield incorrect results on non-true-color displays.
If the `rgb.txt' file is not found (which will be the case if you're
@@ -311,89 +327,72 @@ output.")
;; in some cases checking against the version *is* necessary.
(defconst htmlize-running-xemacs (string-match "XEmacs" emacs-version))
-(eval-and-compile
- ;; save-current-buffer, with-current-buffer, and with-temp-buffer
- ;; are not available in 19.34 and in older XEmacsen. Strictly
- ;; speaking, we should stick to our own namespace and define and use
- ;; htmlize-save-current-buffer, etc. But non-standard special forms
- ;; are a pain because they're not properly fontified or indented and
- ;; because they look weird and ugly. So I'll just go ahead and
- ;; define the real ones if they're not available. If someone
- ;; convinces me that this breaks something, I'll switch to the
- ;; "htmlize-" namespace.
- (unless (fboundp 'save-current-buffer)
- (defmacro save-current-buffer (&rest forms)
- `(let ((__scb_current (current-buffer)))
- (unwind-protect
- (progn ,@forms)
- (set-buffer __scb_current)))))
- (unless (fboundp 'with-current-buffer)
- (defmacro with-current-buffer (buffer &rest forms)
- `(save-current-buffer (set-buffer ,buffer) ,@forms)))
- (unless (fboundp 'with-temp-buffer)
- (defmacro with-temp-buffer (&rest forms)
- (let ((temp-buffer (gensym "tb-")))
- `(let ((,temp-buffer
- (get-buffer-create (generate-new-buffer-name " *temp*"))))
- (unwind-protect
- (with-current-buffer ,temp-buffer
- ,@forms)
- (and (buffer-live-p ,temp-buffer)
- (kill-buffer ,temp-buffer))))))))
-
;; We need a function that efficiently finds the next change of a
-;; property (usually `face'), preferably regardless of whether the
-;; change occurred because of a text property or an extent/overlay.
-;; As it turns out, it is not easy to do that compatibly.
-;;
-;; Under XEmacs, `next-single-property-change' does that. Under GNU
-;; Emacs beginning with version 21, `next-single-char-property-change'
-;; is available and does the same. GNU Emacs 20 had
-;; `next-char-property-change', which we can use. GNU Emacs 19 didn't
-;; provide any means for simultaneously examining overlays and text
-;; properties, so when using Emacs 19.34, we punt and fall back to
-;; `next-single-property-change', thus ignoring overlays altogether.
-
+;; property regardless of whether the change occurred because of a
+;; text property or an extent/overlay.
(cond
(htmlize-running-xemacs
- ;; XEmacs: good.
(defun htmlize-next-change (pos prop &optional limit)
- (next-single-property-change pos prop nil (or limit (point-max)))))
+ (if prop
+ (next-single-char-property-change pos prop nil (or limit (point-max)))
+ (next-property-change pos nil (or limit (point-max)))))
+ (defun htmlize-next-face-change (pos &optional limit)
+ (htmlize-next-change pos 'face limit)))
((fboundp 'next-single-char-property-change)
- ;; GNU Emacs 21: good.
- (defun htmlize-next-change (pos prop &optional limit)
- (next-single-char-property-change pos prop nil limit)))
- ((fboundp 'next-char-property-change)
- ;; GNU Emacs 20: bad, but fixable.
+ ;; GNU Emacs 21+
(defun htmlize-next-change (pos prop &optional limit)
- (let ((done nil)
- (current-value (get-char-property pos prop))
- newpos next-value)
- ;; Loop over positions returned by next-char-property-change
- ;; until the value of PROP changes or we've hit EOB.
- (while (not done)
- (setq newpos (next-char-property-change pos limit)
- next-value (get-char-property newpos prop))
- (cond ((eq newpos pos)
- ;; Possibly at EOB? Whatever, just don't infloop.
- (setq done t))
- ((eq next-value current-value)
- ;; PROP hasn't changed -- keep looping.
- )
- (t
- (setq done t)))
- (setq pos newpos))
+ (if prop
+ (next-single-char-property-change pos prop nil limit)
+ (next-char-property-change pos limit)))
+ (defun htmlize-overlay-faces-at (pos)
+ (delq nil (mapcar (lambda (o) (overlay-get o 'face)) (overlays-at pos))))
+ (defun htmlize-next-face-change (pos &optional limit)
+ ;; (htmlize-next-change pos 'face limit) would skip over entire
+ ;; overlays that specify the `face' property, even when they
+ ;; contain smaller text properties that also specify `face'.
+ ;; Emacs display engine merges those faces, and so must we.
+ (or limit
+ (setq limit (point-max)))
+ (let ((next-prop (next-single-property-change pos 'face nil limit))
+ (overlay-faces (htmlize-overlay-faces-at pos)))
+ (while (progn
+ (setq pos (next-overlay-change pos))
+ (and (< pos next-prop)
+ (equal overlay-faces (htmlize-overlay-faces-at pos)))))
+ (setq pos (min pos next-prop))
+ ;; Additionally, we include the entire region that specifies the
+ ;; `display' property.
+ (when (get-char-property pos 'display)
+ (setq pos (next-single-char-property-change pos 'display nil limit)))
pos)))
(t
- ;; GNU Emacs 19.34: hopeless, cannot properly support overlays.
- (defun htmlize-next-change (pos prop &optional limit)
- (unless limit
- (setq limit (point-max)))
- (let ((res (next-single-property-change pos prop)))
- (if (or (null res)
- (> res limit))
- limit
- res)))))
+ (error "htmlize requires next-single-property-change or \
+next-single-char-property-change")))
+
+(defmacro htmlize-lexlet (&rest letforms)
+ (declare (indent 1) (debug let))
+ (if (and (boundp 'lexical-binding)
+ lexical-binding)
+ `(let ,@letforms)
+ ;; cl extensions have a macro implementing lexical let
+ `(lexical-let ,@letforms)))
+
+;; Simple overlay emulation for XEmacs
+
+(cond
+ (htmlize-running-xemacs
+ (defalias 'htmlize-make-overlay 'make-extent)
+ (defalias 'htmlize-overlay-put 'set-extent-property)
+ (defalias 'htmlize-overlay-get 'extent-property)
+ (defun htmlize-overlays-in (beg end) (extent-list nil beg end))
+ (defalias 'htmlize-delete-overlay 'detach-extent))
+ (t
+ (defalias 'htmlize-make-overlay 'make-overlay)
+ (defalias 'htmlize-overlay-put 'overlay-put)
+ (defalias 'htmlize-overlay-get 'overlay-get)
+ (defalias 'htmlize-overlays-in 'overlays-in)
+ (defalias 'htmlize-delete-overlay 'delete-overlay)))
+
;;; Transformation of buffer text: HTML escapes, untabification, etc.
@@ -419,17 +418,16 @@ output.")
(aref table ?>) "&gt;"
;; Not escaping '"' buys us a measurable speedup. It's only
;; necessary to quote it for strings used in attribute values,
- ;; which htmlize doesn't do.
+ ;; which htmlize doesn't typically do.
;(aref table ?\") "&quot;"
)
table))
;; A cache of HTML representation of non-ASCII characters. Depending
-;; on availability of `encode-char' and the setting of
-;; `htmlize-convert-nonascii-to-entities', this maps non-ASCII
-;; characters to either "&#<code>;" or "<char>" (mapconcat's mapper
-;; must always return strings). It's only filled as characters are
-;; encountered, so that in a buffer with e.g. French text, it will
+;; on the setting of `htmlize-convert-nonascii-to-entities', this maps
+;; non-ASCII characters to either "&#<code>;" or "<char>" (mapconcat's
+;; mapper must always return strings). It's only filled as characters
+;; are encountered, so that in a buffer with e.g. French text, it will
;; only ever contain French accented characters as keys. It's cleared
;; on each entry to htmlize-buffer-1 to allow modifications of
;; `htmlize-convert-nonascii-to-entities' to take effect.
@@ -459,10 +457,9 @@ output.")
;; Latin 1: no need to call encode-char.
(setf (gethash char htmlize-extended-character-cache)
(format "&#%d;" char)))
- ((and (fboundp 'encode-char)
- ;; Must check if encode-char works for CHAR;
- ;; it fails for Arabic and possibly elsewhere.
- (encode-char char 'ucs))
+ ((encode-char char 'ucs)
+ ;; Must check if encode-char works for CHAR;
+ ;; it fails for Arabic and possibly elsewhere.
(setf (gethash char htmlize-extended-character-cache)
(format "&#%d;" (encode-char char 'ucs))))
(t
@@ -472,63 +469,249 @@ output.")
(char-to-string char)))))
string "")))
+(defun htmlize-attr-escape (string)
+ ;; Like htmlize-protect-string, but also escapes double-quoted
+ ;; strings to make it usable in attribute values.
+ (setq string (htmlize-protect-string string))
+ (if (not (string-match "\"" string))
+ string
+ (mapconcat (lambda (char)
+ (if (eql char ?\")
+ "&quot;"
+ (char-to-string char)))
+ string "")))
+
+(defsubst htmlize-concat (list)
+ (if (and (consp list) (null (cdr list)))
+ ;; Don't create a new string in the common case where the list only
+ ;; consists of one element.
+ (car list)
+ (apply #'concat list)))
+
+(defun htmlize-format-link (linkprops text)
+ (let ((uri (if (stringp linkprops)
+ linkprops
+ (plist-get linkprops :uri)))
+ (escaped-text (htmlize-protect-string text)))
+ (if uri
+ (format "<a href=\"%s\">%s</a>" (htmlize-attr-escape uri) escaped-text)
+ escaped-text)))
+
+(defun htmlize-escape-or-link (string)
+ ;; Escape STRING and/or add hyperlinks. STRING comes from a
+ ;; `display' property.
+ (let ((pos 0) (end (length string)) outlist)
+ (while (< pos end)
+ (let* ((link (get-char-property pos 'htmlize-link string))
+ (next-link-change (next-single-property-change
+ pos 'htmlize-link string end))
+ (chunk (substring string pos next-link-change)))
+ (push
+ (cond (link
+ (htmlize-format-link link chunk))
+ ((get-char-property 0 'htmlize-literal chunk)
+ chunk)
+ (t
+ (htmlize-protect-string chunk)))
+ outlist)
+ (setq pos next-link-change)))
+ (htmlize-concat (nreverse outlist))))
+
+(defun htmlize-display-prop-to-html (display text)
+ (let (desc)
+ (cond ((stringp display)
+ ;; Emacs ignores recursive display properties.
+ (htmlize-escape-or-link display))
+ ((not (eq (car-safe display) 'image))
+ (htmlize-protect-string text))
+ ((null (setq desc (funcall htmlize-transform-image
+ (cdr display) text)))
+ (htmlize-escape-or-link text))
+ ((stringp desc)
+ (htmlize-escape-or-link desc))
+ (t
+ (htmlize-generate-image desc text)))))
+
+(defun htmlize-string-to-html (string)
+ ;; Convert the string to HTML, including images attached as
+ ;; `display' property and links as `htmlize-link' property. In a
+ ;; string without images or links, this is equivalent to
+ ;; `htmlize-protect-string'.
+ (let ((pos 0) (end (length string)) outlist)
+ (while (< pos end)
+ (let* ((display (get-char-property pos 'display string))
+ (next-display-change (next-single-property-change
+ pos 'display string end))
+ (chunk (substring string pos next-display-change)))
+ (push
+ (if display
+ (htmlize-display-prop-to-html display chunk)
+ (htmlize-escape-or-link chunk))
+ outlist)
+ (setq pos next-display-change)))
+ (htmlize-concat (nreverse outlist))))
+
+(defun htmlize-default-transform-image (imgprops _text)
+ "Default transformation of image descriptor to something usable in HTML.
+
+If `htmlize-use-images' is nil, the function always returns nil, meaning
+use original text. Otherwise, it tries to find the image for images that
+specify a file name. If `htmlize-force-inline-images' is non-nil, it also
+converts the :file attribute to :data and returns the modified property
+list."
+ (when htmlize-use-images
+ (when (plist-get imgprops :file)
+ (let ((location (plist-get (cdr (find-image (list imgprops))) :file)))
+ (when location
+ (setq imgprops (plist-put (copy-list imgprops) :file location)))))
+ (if htmlize-force-inline-images
+ (let ((location (plist-get imgprops :file))
+ data)
+ (when location
+ (with-temp-buffer
+ (condition-case nil
+ (progn
+ (insert-file-contents-literally location)
+ (setq data (buffer-string)))
+ (error nil))))
+ ;; if successful, return the new plist, otherwise return
+ ;; nil, which will use the original text
+ (and data
+ (plist-put (plist-put imgprops :file nil)
+ :data data)))
+ imgprops)))
+
+(defun htmlize-alt-text (_imgprops origtext)
+ (and (/= (length origtext) 0)
+ (<= (length origtext) htmlize-max-alt-text)
+ (not (string-match "[\0-\x1f]" origtext))
+ origtext))
+
+(defun htmlize-generate-image (imgprops origtext)
+ (let* ((alt-text (htmlize-alt-text imgprops origtext))
+ (alt-attr (if alt-text
+ (format " alt=\"%s\"" (htmlize-attr-escape alt-text))
+ "")))
+ (cond ((plist-get imgprops :file)
+ ;; Try to find the image in image-load-path
+ (let* ((found-props (cdr (find-image (list imgprops))))
+ (file (or (plist-get found-props :file)
+ (plist-get imgprops :file))))
+ (format "<img src=\"%s\"%s />"
+ (htmlize-attr-escape (file-relative-name file))
+ alt-attr)))
+ ((plist-get imgprops :data)
+ (format "<img src=\"data:image/%s;base64,%s\"%s />"
+ (or (plist-get imgprops :type) "")
+ (base64-encode-string (plist-get imgprops :data))
+ alt-attr)))))
+
(defconst htmlize-ellipsis "...")
(put-text-property 0 (length htmlize-ellipsis) 'htmlize-ellipsis t htmlize-ellipsis)
+(defun htmlize-match-inv-spec (inv)
+ (member* inv buffer-invisibility-spec
+ :key (lambda (i)
+ (if (symbolp i) i (car i)))))
+
+(defun htmlize-decode-invisibility-spec (invisible)
+ ;; Return t, nil, or `ellipsis', depending on how invisible text should be inserted.
+
+ (if (not (listp buffer-invisibility-spec))
+ ;; If buffer-invisibility-spec is not a list, then all
+ ;; characters with non-nil `invisible' property are visible.
+ (not invisible)
+
+ ;; Otherwise, the value of a non-nil `invisible' property can be:
+ ;; 1. a symbol -- make the text invisible if it matches
+ ;; buffer-invisibility-spec.
+ ;; 2. a list of symbols -- make the text invisible if
+ ;; any symbol in the list matches
+ ;; buffer-invisibility-spec.
+ ;; If the match of buffer-invisibility-spec has a non-nil
+ ;; CDR, replace the invisible text with an ellipsis.
+ (let ((match (if (symbolp invisible)
+ (htmlize-match-inv-spec invisible)
+ (some #'htmlize-match-inv-spec invisible))))
+ (cond ((null match) t)
+ ((cdr-safe (car match)) 'ellipsis)
+ (t nil)))))
+
+(defun htmlize-add-before-after-strings (beg end text)
+ ;; Find overlays specifying before-string and after-string in [beg,
+ ;; pos). If any are found, splice them into TEXT and return the new
+ ;; text.
+ (let (additions)
+ (dolist (overlay (overlays-in beg end))
+ (let ((before (overlay-get overlay 'before-string))
+ (after (overlay-get overlay 'after-string)))
+ (when after
+ (push (cons (- (overlay-end overlay) beg)
+ after)
+ additions))
+ (when before
+ (push (cons (- (overlay-start overlay) beg)
+ before)
+ additions))))
+ (if additions
+ (let ((textlist nil)
+ (strpos 0))
+ (dolist (add (stable-sort additions #'< :key #'car))
+ (let ((addpos (car add))
+ (addtext (cdr add)))
+ (push (substring text strpos addpos) textlist)
+ (push addtext textlist)
+ (setq strpos addpos)))
+ (push (substring text strpos) textlist)
+ (apply #'concat (nreverse textlist)))
+ text)))
+
+(defun htmlize-copy-prop (prop beg end string)
+ ;; Copy the specified property from the specified region of the
+ ;; buffer to the target string. We cannot rely on Emacs to copy the
+ ;; property because we want to handle properties coming from both
+ ;; text properties and overlays.
+ (let ((pos beg))
+ (while (< pos end)
+ (let ((value (get-char-property pos prop))
+ (next-change (htmlize-next-change pos prop end)))
+ (when value
+ (put-text-property (- pos beg) (- next-change beg)
+ prop value string))
+ (setq pos next-change)))))
+
+(defun htmlize-get-text-with-display (beg end)
+ ;; Like buffer-substring-no-properties, except it copies the
+ ;; `display' property from the buffer, if found.
+ (let ((text (buffer-substring-no-properties beg end)))
+ (htmlize-copy-prop 'display beg end text)
+ (htmlize-copy-prop 'htmlize-link beg end text)
+ (unless htmlize-running-xemacs
+ (setq text (htmlize-add-before-after-strings beg end text)))
+ text))
+
(defun htmlize-buffer-substring-no-invisible (beg end)
;; Like buffer-substring-no-properties, but don't copy invisible
;; parts of the region. Where buffer-substring-no-properties
;; mandates an ellipsis to be shown, htmlize-ellipsis is inserted.
(let ((pos beg)
- visible-list invisible show next-change)
+ visible-list invisible show last-show next-change)
;; Iterate over the changes in the `invisible' property and filter
;; out the portions where it's non-nil, i.e. where the text is
;; invisible.
(while (< pos end)
(setq invisible (get-char-property pos 'invisible)
- next-change (htmlize-next-change pos 'invisible end))
- (if (not (listp buffer-invisibility-spec))
- ;; If buffer-invisibility-spec is not a list, then all
- ;; characters with non-nil `invisible' property are visible.
- (setq show (not invisible))
- ;; Otherwise, the value of a non-nil `invisible' property can be:
- ;; 1. a symbol -- make the text invisible if it matches
- ;; buffer-invisibility-spec.
- ;; 2. a list of symbols -- make the text invisible if
- ;; any symbol in the list matches
- ;; buffer-invisibility-spec.
- ;; If the match of buffer-invisibility-spec has a non-nil
- ;; CDR, replace the invisible text with an ellipsis.
- (let (match)
- (if (symbolp invisible)
- (setq match (member* invisible buffer-invisibility-spec
- :key (lambda (i)
- (if (symbolp i) i (car i)))))
- (setq match (block nil
- (dolist (elem invisible)
- (let ((m (member*
- elem buffer-invisibility-spec
- :key (lambda (i)
- (if (symbolp i) i (car i))))))
- (when m (return m))))
- nil)))
- (setq show (cond ((null match) t)
- ((and (cdr-safe (car match))
- ;; Conflate successive ellipses.
- (not (eq show htmlize-ellipsis)))
- htmlize-ellipsis)
- (t nil)))))
+ next-change (htmlize-next-change pos 'invisible end)
+ show (htmlize-decode-invisibility-spec invisible))
(cond ((eq show t)
- (push (buffer-substring-no-properties pos next-change) visible-list))
- ((stringp show)
- (push show visible-list)))
- (setq pos next-change))
- (if (= (length visible-list) 1)
- ;; If VISIBLE-LIST consists of only one element, return it
- ;; without concatenation. This avoids additional consing in
- ;; regions without any invisible text.
- (car visible-list)
- (apply #'concat (nreverse visible-list)))))
+ (push (htmlize-get-text-with-display pos next-change)
+ visible-list))
+ ((and (eq show 'ellipsis)
+ (not (eq last-show 'ellipsis))
+ ;; Conflate successive ellipses.
+ (push htmlize-ellipsis visible-list))))
+ (setq pos next-change last-show show))
+ (htmlize-concat (nreverse visible-list))))
(defun htmlize-trim-ellipsis (text)
;; Remove htmlize-ellipses ("...") from the beginning of TEXT if it
@@ -565,8 +748,13 @@ output.")
(incf column (- match-pos last-match))
;; Calculate tab size based on tab-width and COLUMN.
(setq tab-size (- tab-width (% column tab-width)))
- ;; Expand the tab.
- (push (aref htmlize-tab-spaces tab-size) chunks)
+ ;; Expand the tab, carefully recreating the `display'
+ ;; property if one was on the TAB.
+ (let ((display (get-text-property match-pos 'display text))
+ (expanded-tab (aref htmlize-tab-spaces tab-size)))
+ (when display
+ (put-text-property 0 tab-size 'display display expanded-tab))
+ (push expanded-tab chunks))
(incf column tab-size)
(setq chunk-start (1+ match-pos)))
(t
@@ -581,42 +769,64 @@ output.")
;; Push the remaining chunk.
(push (substring text chunk-start) chunks))
;; Generate the output from the available chunks.
- (apply #'concat (nreverse chunks)))))
+ (htmlize-concat (nreverse chunks)))))
+
+(defun htmlize-extract-text (beg end trailing-ellipsis)
+ ;; Extract buffer text, sans the invisible parts. Then
+ ;; untabify it and escape the HTML metacharacters.
+ (let ((text (htmlize-buffer-substring-no-invisible beg end)))
+ (when trailing-ellipsis
+ (setq text (htmlize-trim-ellipsis text)))
+ ;; If TEXT ends up empty, don't change trailing-ellipsis.
+ (when (> (length text) 0)
+ (setq trailing-ellipsis
+ (get-text-property (1- (length text))
+ 'htmlize-ellipsis text)))
+ (setq text (htmlize-untabify text (current-column)))
+ (setq text (htmlize-string-to-html text))
+ (values text trailing-ellipsis)))
(defun htmlize-despam-address (string)
- "Replace every occurrence of '@' in STRING with &#64;.
-`htmlize-make-hyperlinks' uses this to spam-protect mailto links
-without modifying their meaning."
+ "Replace every occurrence of '@' in STRING with %40.
+This is used to protect mailto links without modifying their meaning."
;; Suggested by Ville Skytta.
(while (string-match "@" string)
- (setq string (replace-match "&#64;" nil t string)))
+ (setq string (replace-match "%40" nil t string)))
string)
-(defun htmlize-make-hyperlinks ()
- "Make hyperlinks in HTML."
- ;; Function originally submitted by Ville Skytta. Rewritten by
- ;; Hrvoje Niksic, then modified by Ville Skytta and Hrvoje Niksic.
- (goto-char (point-min))
- (while (re-search-forward
- "&lt;\\(\\(mailto:\\)?\\([-=+_.a-zA-Z0-9]+@[-_.a-zA-Z0-9]+\\)\\)&gt;"
- nil t)
- (let ((address (match-string 3))
- (link-text (match-string 1)))
- (delete-region (match-beginning 0) (match-end 0))
- (insert "&lt;<a href=\"mailto:"
- (htmlize-despam-address address)
- "\">"
- (htmlize-despam-address link-text)
- "</a>&gt;")))
- (goto-char (point-min))
- (while (re-search-forward "&lt;\\(\\(URL:\\)?\\([a-zA-Z]+://[^;]+\\)\\)&gt;"
- nil t)
- (let ((url (match-string 3))
- (link-text (match-string 1)))
- (delete-region (match-beginning 0) (match-end 0))
- (insert "&lt;<a href=\"" url "\">" link-text "</a>&gt;"))))
+(defun htmlize-make-tmp-overlay (beg end props)
+ (let ((overlay (htmlize-make-overlay beg end)))
+ (htmlize-overlay-put overlay 'htmlize-tmp-overlay t)
+ (while props
+ (htmlize-overlay-put overlay (pop props) (pop props)))
+ overlay))
+
+(defun htmlize-delete-tmp-overlays ()
+ (dolist (overlay (htmlize-overlays-in (point-min) (point-max)))
+ (when (htmlize-overlay-get overlay 'htmlize-tmp-overlay)
+ (htmlize-delete-overlay overlay))))
+
+(defun htmlize-make-link-overlay (beg end uri)
+ (htmlize-make-tmp-overlay beg end `(htmlize-link (:uri ,uri))))
-;; Tests for htmlize-make-hyperlinks:
+(defun htmlize-create-auto-links ()
+ "Add `htmlize-link' property to all mailto links in the buffer."
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward
+ "<\\(\\(mailto:\\)?\\([-=+_.a-zA-Z0-9]+@[-_.a-zA-Z0-9]+\\)\\)>"
+ nil t)
+ (let* ((address (match-string 3))
+ (beg (match-beginning 0)) (end (match-end 0))
+ (uri (concat "mailto:" (htmlize-despam-address address))))
+ (htmlize-make-link-overlay beg end uri)))
+ (goto-char (point-min))
+ (while (re-search-forward "<\\(\\(URL:\\)?\\([a-zA-Z]+://[^;>]+\\)\\)>"
+ nil t)
+ (htmlize-make-link-overlay
+ (match-beginning 0) (match-end 0) (match-string 3)))))
+
+;; Tests for htmlize-create-auto-links:
;; <mailto:hniksic@xemacs.org>
;; <http://fly.srk.fer.hr>
@@ -625,6 +835,13 @@ without modifying their meaning."
;; <hniksic@xemacs.org>
;; <xalan-dev-sc.10148567319.hacuhiucknfgmpfnjcpg-john=doe.com@xml.apache.org>
+(defun htmlize-shadow-form-feeds ()
+ (let ((s "\n<hr />"))
+ (put-text-property 0 (length s) 'htmlize-literal t s)
+ (let ((disp `(display ,s)))
+ (while (re-search-forward "\n\^L" nil t)
+ (htmlize-make-tmp-overlay (match-beginning 0) (match-end 0) disp)))))
+
(defun htmlize-defang-local-variables ()
;; Juri Linkov reports that an HTML-ized "Local variables" can lead
;; visiting the HTML to fail with "Local variables list is not
@@ -637,15 +854,12 @@ without modifying their meaning."
;;; Color handling.
-(if (fboundp 'locate-file)
- (defalias 'htmlize-locate-file 'locate-file)
- (defun htmlize-locate-file (file path)
- (dolist (dir path nil)
- (when (file-exists-p (expand-file-name file dir))
- (return (expand-file-name file dir))))))
-
(defvar htmlize-x-library-search-path
- '("/usr/X11R6/lib/X11/"
+ `(,data-directory
+ "/etc/X11/rgb.txt"
+ "/usr/share/X11/rgb.txt"
+ ;; the remainder of this list really belongs in a museum
+ "/usr/X11R6/lib/X11/"
"/usr/X11R5/lib/X11/"
"/usr/lib/X11R6/X11/"
"/usr/lib/X11R5/X11/"
@@ -675,7 +889,7 @@ If RGB-FILE is nil, the function will try hard to find a suitable file
in the system directories.
If no rgb.txt file is found, return nil."
- (let ((rgb-file (or rgb-file (htmlize-locate-file
+ (let ((rgb-file (or rgb-file (locate-file
"rgb.txt"
htmlize-x-library-search-path)))
(hash nil))
@@ -796,18 +1010,14 @@ If no rgb.txt file is found, return nil."
(t
;; We're getting the RGB components from Emacs.
(let ((rgb
- ;; Here I cannot conditionalize on (fboundp ...)
- ;; because ps-print under some versions of GNU Emacs
- ;; defines its own dummy version of
- ;; `color-instance-rgb-components'.
- (if htmlize-running-xemacs
+ (if (fboundp 'color-instance-rgb-components)
(mapcar (lambda (arg)
(/ arg 256))
(color-instance-rgb-components
(make-color-instance color)))
(mapcar (lambda (arg)
(/ arg 256))
- (x-color-values color)))))
+ (color-values color)))))
(when rgb
(setq rgb-string (apply #'format "#%02x%02x%02x" rgb))))))
;; If RGB-STRING is still nil, it means the color cannot be found,
@@ -866,12 +1076,37 @@ If no rgb.txt file is found, return nil."
;; Only works in Emacs 21 and later.
(let ((size-list
(loop
- for f = face then (ignore-errors (face-attribute f :inherit)) ;?????
+ for f = face then (face-attribute f :inherit)
until (or (not f) (eq f 'unspecified))
- for h = (ignore-errors (face-attribute f :height)) ;???????
+ for h = (face-attribute f :height)
collect (if (eq h 'unspecified) nil h))))
(reduce 'htmlize-merge-size (cons nil size-list))))
+(defun htmlize-face-css-name (face)
+ ;; Generate the css-name property for the given face. Emacs places
+ ;; no restrictions on the names of symbols that represent faces --
+ ;; any characters may be in the name, even control chars. We try
+ ;; hard to beat the face name into shape, both esthetically and
+ ;; according to CSS1 specs.
+ (let ((name (downcase (symbol-name face))))
+ (when (string-match "\\`font-lock-" name)
+ ;; font-lock-FOO-face -> FOO.
+ (setq name (replace-match "" t t name)))
+ (when (string-match "-face\\'" name)
+ ;; Drop the redundant "-face" suffix.
+ (setq name (replace-match "" t t name)))
+ (while (string-match "[^-a-zA-Z0-9]" name)
+ ;; Drop the non-alphanumerics.
+ (setq name (replace-match "X" t t name)))
+ (when (string-match "\\`[-0-9]" name)
+ ;; CSS identifiers may not start with a digit.
+ (setq name (concat "X" name)))
+ ;; After these transformations, the face could come out empty.
+ (when (equal name "")
+ (setq name "face"))
+ ;; Apply the prefix.
+ (concat htmlize-css-name-prefix name)))
+
(defun htmlize-face-to-fstruct (face)
"Convert Emacs face FACE to fstruct."
(let ((fstruct (make-htmlize-fstruct
@@ -879,87 +1114,53 @@ If no rgb.txt file is found, return nil."
(htmlize-face-foreground face))
:background (htmlize-color-to-rgb
(htmlize-face-background face)))))
- (cond (htmlize-running-xemacs
- ;; XEmacs doesn't provide a way to detect whether a face is
- ;; bold or italic, so we need to examine the font instance.
- ;; #### This probably doesn't work under MS Windows and/or
- ;; GTK devices. I'll need help with those.
- (let* ((font-instance (face-font-instance face))
- (props (font-instance-properties font-instance)))
- (when (equalp (cdr (assq 'WEIGHT_NAME props)) "bold")
- (setf (htmlize-fstruct-boldp fstruct) t))
- (when (or (equalp (cdr (assq 'SLANT props)) "i")
- (equalp (cdr (assq 'SLANT props)) "o"))
- (setf (htmlize-fstruct-italicp fstruct) t))
- (setf (htmlize-fstruct-strikep fstruct)
- (face-strikethru-p face))
- (setf (htmlize-fstruct-underlinep fstruct)
- (face-underline-p face))))
- ((fboundp 'face-attribute)
- ;; GNU Emacs 21 and further.
- (dolist (attr '(:weight :slant :underline :overline :strike-through))
- (let ((value (if (>= emacs-major-version 22)
- ;; Use the INHERIT arg in GNU Emacs 22.
- (face-attribute face attr nil t)
- ;; Otherwise, fake it.
- (let ((face face))
- (while (and (eq (face-attribute face attr)
- 'unspecified)
- (not (eq (face-attribute face :inherit)
- 'unspecified)))
- (setq face (face-attribute face :inherit)))
- (face-attribute face attr)))))
- (when (and value (not (eq value 'unspecified)))
- (htmlize-face-emacs21-attr fstruct attr value))))
- (let ((size (htmlize-face-size face)))
- (unless (eql size 1.0) ; ignore non-spec
- (setf (htmlize-fstruct-size fstruct) size))))
- (t
- ;; Older GNU Emacs. Some of these functions are only
- ;; available under Emacs 20+, hence the guards.
- (when (fboundp 'face-bold-p)
- (setf (htmlize-fstruct-boldp fstruct) (face-bold-p face)))
- (when (fboundp 'face-italic-p)
- (setf (htmlize-fstruct-italicp fstruct) (face-italic-p face)))
- (setf (htmlize-fstruct-underlinep fstruct)
- (face-underline-p face))))
- ;; Generate the css-name property. Emacs places no restrictions
- ;; on the names of symbols that represent faces -- any characters
- ;; may be in the name, even ^@. We try hard to beat the face name
- ;; into shape, both esthetically and according to CSS1 specs.
- (setf (htmlize-fstruct-css-name fstruct)
- (let ((name (downcase (symbol-name face))))
- (when (string-match "\\`font-lock-" name)
- ;; Change font-lock-FOO-face to FOO.
- (setq name (replace-match "" t t name)))
- (when (string-match "-face\\'" name)
- ;; Drop the redundant "-face" suffix.
- (setq name (replace-match "" t t name)))
- (while (string-match "[^-a-zA-Z0-9]" name)
- ;; Drop the non-alphanumerics.
- (setq name (replace-match "X" t t name)))
- (when (string-match "\\`[-0-9]" name)
- ;; CSS identifiers may not start with a digit.
- (setq name (concat "X" name)))
- ;; After these transformations, the face could come
- ;; out empty.
- (when (equal name "")
- (setq name "face"))
- ;; Apply the prefix.
- (setq name (concat htmlize-css-name-prefix name))
- name))
+ (if htmlize-running-xemacs
+ ;; XEmacs doesn't provide a way to detect whether a face is
+ ;; bold or italic, so we need to examine the font instance.
+ (let* ((font-instance (face-font-instance face))
+ (props (font-instance-properties font-instance)))
+ (when (equalp (cdr (assq 'WEIGHT_NAME props)) "bold")
+ (setf (htmlize-fstruct-boldp fstruct) t))
+ (when (or (equalp (cdr (assq 'SLANT props)) "i")
+ (equalp (cdr (assq 'SLANT props)) "o"))
+ (setf (htmlize-fstruct-italicp fstruct) t))
+ (setf (htmlize-fstruct-strikep fstruct)
+ (face-strikethru-p face))
+ (setf (htmlize-fstruct-underlinep fstruct)
+ (face-underline-p face)))
+ ;; GNU Emacs
+ (dolist (attr '(:weight :slant :underline :overline :strike-through))
+ (let ((value (if (>= emacs-major-version 22)
+ ;; Use the INHERIT arg in GNU Emacs 22.
+ (face-attribute face attr nil t)
+ ;; Otherwise, fake it.
+ (let ((face face))
+ (while (and (eq (face-attribute face attr)
+ 'unspecified)
+ (not (eq (face-attribute face :inherit)
+ 'unspecified)))
+ (setq face (face-attribute face :inherit)))
+ (face-attribute face attr)))))
+ (when (and value (not (eq value 'unspecified)))
+ (htmlize-face-emacs21-attr fstruct attr value))))
+ (let ((size (htmlize-face-size face)))
+ (unless (eql size 1.0) ; ignore non-spec
+ (setf (htmlize-fstruct-size fstruct) size))))
+ (setf (htmlize-fstruct-css-name fstruct) (htmlize-face-css-name face))
fstruct))
(defmacro htmlize-copy-attr-if-set (attr-list dest source)
- ;; Expand the code of the type
- ;; (and (htmlize-fstruct-ATTR source)
- ;; (setf (htmlize-fstruct-ATTR dest) (htmlize-fstruct-ATTR source)))
+ ;; Generate code with the following pattern:
+ ;; (progn
+ ;; (when (htmlize-fstruct-ATTR source)
+ ;; (setf (htmlize-fstruct-ATTR dest) (htmlize-fstruct-ATTR source)))
+ ;; ...)
;; for the given list of boolean attributes.
(cons 'progn
(loop for attr in attr-list
for attr-sym = (intern (format "htmlize-fstruct-%s" attr))
- collect `(and (,attr-sym ,source)
- (setf (,attr-sym ,dest) (,attr-sym ,source))))))
+ collect `(when (,attr-sym ,source)
+ (setf (,attr-sym ,dest) (,attr-sym ,source))))))
(defun htmlize-merge-size (merged next)
;; Calculate the size of the merge of MERGED and NEXT.
@@ -1019,32 +1220,39 @@ If no rgb.txt file is found, return nil."
(setf (htmlize-fstruct-css-name fstruct) "ATTRLIST")
fstruct))
-(defun htmlize-face-list-p (face-prop)
- "Return non-nil if FACE-PROP is a list of faces, nil otherwise."
- ;; If not for attrlists, this would return (listp face-prop). This
- ;; way we have to be more careful because attrlist is also a list!
- (cond
- ((eq face-prop nil)
- ;; FACE-PROP being nil means empty list (no face), so return t.
- t)
- ((symbolp face-prop)
- ;; A symbol other than nil means that it's only one face, so return
- ;; nil.
- nil)
- ((not (consp face-prop))
- ;; Huh? Not a symbol or cons -- treat it as a single element.
- nil)
- (t
- ;; We know that FACE-PROP is a cons: check whether it looks like an
- ;; ATTRLIST.
- (let* ((car (car face-prop))
- (attrlist-p (and (symbolp car)
- (or (eq car 'foreground-color)
- (eq car 'background-color)
- (eq (aref (symbol-name car) 0) ?:)))))
- ;; If FACE-PROP is not an ATTRLIST, it means it's a list of
- ;; faces.
- (not attrlist-p)))))
+(defun htmlize-decode-face-prop (prop)
+ "Turn face property PROP into a list of face-like objects."
+ ;; PROP can be a symbol naming a face, a string naming such a
+ ;; symbol, a cons (foreground-color . COLOR) or (background-color
+ ;; COLOR), a property list (:attr1 val1 :attr2 val2 ...), or a list
+ ;; of any of those.
+ ;;
+ ;; (htmlize-decode-face-prop 'face) -> (face)
+ ;; (htmlize-decode-face-prop '(face1 face2)) -> (face1 face2)
+ ;; (htmlize-decode-face-prop '(:attr "val")) -> ((:attr "val"))
+ ;; (htmlize-decode-face-prop '((:attr "val") face (foreground-color "red")))
+ ;; -> ((:attr "val") face (foreground-color "red"))
+ ;;
+ ;; Unrecognized atoms or non-face symbols/strings are silently
+ ;; stripped away.
+ (cond ((null prop)
+ nil)
+ ((symbolp prop)
+ (and (facep prop)
+ (list prop)))
+ ((stringp prop)
+ (and (facep (intern-soft prop))
+ (list prop)))
+ ((atom prop)
+ nil)
+ ((and (symbolp (car prop))
+ (eq ?: (aref (symbol-name (car prop)) 0)))
+ (list prop))
+ ((or (eq (car prop) 'foreground-color)
+ (eq (car prop) 'background-color))
+ (list prop))
+ (t
+ (apply #'nconc (mapcar #'htmlize-decode-face-prop prop)))))
(defun htmlize-make-face-map (faces)
;; Return a hash table mapping Emacs faces to htmlize's fstructs.
@@ -1107,22 +1315,14 @@ property and by buffer overlays that specify `face'."
(while (< pos (point-max))
(setq face-prop (get-text-property pos 'face)
next (or (next-single-property-change pos 'face) (point-max)))
- ;; FACE-PROP can be a face/attrlist or a list thereof.
- (setq faces (if (htmlize-face-list-p face-prop)
- (nunion (mapcar #'htmlize-unstringify-face face-prop)
- faces :test 'equal)
- (adjoin (htmlize-unstringify-face face-prop)
- faces :test 'equal)))
+ (setq faces (nunion (htmlize-decode-face-prop face-prop)
+ faces :test 'equal))
(setq pos next)))
;; Faces used by overlays.
(dolist (overlay (overlays-in (point-min) (point-max)))
(let ((face-prop (overlay-get overlay 'face)))
- ;; FACE-PROP can be a face/attrlist or a list thereof.
- (setq faces (if (htmlize-face-list-p face-prop)
- (nunion (mapcar #'htmlize-unstringify-face face-prop)
- faces :test 'equal)
- (adjoin (htmlize-unstringify-face face-prop)
- faces :test 'equal))))))
+ (setq faces (nunion (htmlize-decode-face-prop face-prop)
+ faces :test 'equal)))))
faces))
;; htmlize-faces-at-point returns the faces in use at point. The
@@ -1156,10 +1356,7 @@ property and by buffer overlays that specify `face'."
(let (all-faces)
;; Faces from text properties.
(let ((face-prop (get-text-property (point) 'face)))
- (setq all-faces (if (htmlize-face-list-p face-prop)
- (nreverse (mapcar #'htmlize-unstringify-face
- face-prop))
- (list (htmlize-unstringify-face face-prop)))))
+ (setq all-faces (htmlize-decode-face-prop face-prop)))
;; Faces from overlays.
(let ((overlays
;; Collect overlays at point that specify `face'.
@@ -1189,35 +1386,26 @@ property and by buffer overlays that specify `face'."
:key (lambda (o)
(or (overlay-get o 'priority) 0))))
(dolist (overlay overlays)
- (setq face-prop (overlay-get overlay 'face))
- (setq list (if (htmlize-face-list-p face-prop)
- (nconc (nreverse (mapcar
- #'htmlize-unstringify-face
- face-prop))
- list)
- (cons (htmlize-unstringify-face face-prop) list))))
+ (setq face-prop (overlay-get overlay 'face)
+ list (nconc (htmlize-decode-face-prop face-prop) list)))
;; Under "Merging Faces" the manual explicitly states
;; that faces specified by overlays take precedence over
;; faces specified by text properties.
(setq all-faces (nconc all-faces list)))
all-faces))))
-;; htmlize supports generating HTML in two several fundamentally
-;; different ways, one with the use of CSS and nested <span> tags, and
-;; the other with the use of the old <font> tags. Rather than adding
-;; a bunch of ifs to many places, we take a semi-OO approach.
-;; `htmlize-buffer-1' calls a number of "methods", which indirect to
-;; the functions that depend on `htmlize-output-type'. The currently
-;; used methods are `doctype', `insert-head', `body-tag', and
-;; `insert-text'. Not all output types define all methods.
+;; htmlize supports generating HTML in several flavors, some of which
+;; use CSS, and others the <font> element. We take an OO approach and
+;; define "methods" that indirect to the functions that depend on
+;; `htmlize-output-type'. The currently used methods are `doctype',
+;; `insert-head', `body-tag', and `text-markup'. Not all output types
+;; define all methods.
;;
;; Methods are called either with (htmlize-method METHOD ARGS...)
;; special form, or by accessing the function with
;; (htmlize-method-function 'METHOD) and calling (funcall FUNCTION).
;; The latter form is useful in tight loops because `htmlize-method'
;; conses.
-;;
-;; Currently defined output types are `css' and `font'.
(defmacro htmlize-method (method &rest args)
;; Expand to (htmlize-TYPE-METHOD ...ARGS...). TYPE is the value of
@@ -1254,34 +1442,14 @@ it's called with the same value of KEY. All other times, the cached
(defun htmlize-default-doctype ()
nil ; no doc-string
- ;; According to DTDs published by the W3C, it is illegal to embed
- ;; <font> in <pre>. This makes sense in general, but is bad for
- ;; htmlize's intended usage of <font> to specify the document color.
-
- ;; To make generated HTML legal, htmlize's `font' mode used to
- ;; specify the SGML declaration of "HTML Pro" DTD here. HTML Pro
- ;; aka Silmaril DTD was a project whose goal was to produce a GPL'ed
- ;; DTD that would encompass all the incompatible HTML extensions
- ;; procured by Netscape, MSIE, and other players in the field.
- ;; Apparently the project got abandoned, the last available version
- ;; being "Draft 0 Revision 11" from January 1997, as documented at
- ;; <http://imbolc.ucc.ie/~pflynn/articles/htmlpro.html>.
-
- ;; Since by now HTML Pro is remembered by none but the most die-hard
- ;; early-web-days nostalgics and used by not even them, there is no
- ;; use in specifying it. So we return the standard HTML 4.0
- ;; declaration, which makes generated HTML technically illegal. If
- ;; you have a problem with that, use the `css' engine designed to
- ;; create fully conforming HTML.
-
+ ;; Note that the `font' output is technically invalid under this DTD
+ ;; because the DTD doesn't allow embedding <font> in <pre>.
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">"
-
- ;; Now-abandoned HTML Pro declaration.
- ;"<!DOCTYPE HTML PUBLIC \"+//Silmaril//DTD HTML Pro v0r11 19970101//EN\">"
)
(defun htmlize-default-body-tag (face-map)
nil ; no doc-string
+ face-map ; shut up the byte-compiler
"<body>")
;;; CSS based output support.
@@ -1347,18 +1515,21 @@ it's called with the same value of KEY. All other times, the cached
(insert htmlize-hyperlink-style
" -->\n </style>\n"))
-(defun htmlize-css-insert-text (text fstruct-list buffer)
- ;; Insert TEXT colored with FACES into BUFFER. In CSS mode, this is
- ;; easy: just nest the text in one <span class=...> tag for each
- ;; face in FSTRUCT-LIST.
+(defun htmlize-css-text-markup (fstruct-list buffer)
+ ;; Open the markup needed to insert text colored with FACES into
+ ;; BUFFER. Return the function that closes the markup.
+
+ ;; In CSS mode, this is easy: just nest the text in one <span
+ ;; class=...> tag for each face in FSTRUCT-LIST.
(dolist (fstruct fstruct-list)
(princ "<span class=\"" buffer)
(princ (htmlize-fstruct-css-name fstruct) buffer)
(princ "\">" buffer))
- (princ text buffer)
- (dolist (fstruct fstruct-list)
- (ignore fstruct) ; shut up the byte-compiler
- (princ "</span>" buffer)))
+ (htmlize-lexlet ((fstruct-list fstruct-list) (buffer buffer))
+ (lambda ()
+ (dolist (fstruct fstruct-list)
+ (ignore fstruct) ; shut up the byte-compiler
+ (princ "</span>" buffer)))))
;; `inline-css' output support.
@@ -1367,7 +1538,7 @@ it's called with the same value of KEY. All other times, the cached
(mapconcat #'identity (htmlize-css-specs (gethash 'default face-map))
" ")))
-(defun htmlize-inline-css-insert-text (text fstruct-list buffer)
+(defun htmlize-inline-css-text-markup (fstruct-list buffer)
(let* ((merged (htmlize-merge-faces fstruct-list))
(style (htmlize-memoize
merged
@@ -1378,9 +1549,10 @@ it's called with the same value of KEY. All other times, the cached
(princ "<span style=\"" buffer)
(princ style buffer)
(princ "\">" buffer))
- (princ text buffer)
- (when style
- (princ "</span>" buffer))))
+ (htmlize-lexlet ((style style) (buffer buffer))
+ (lambda ()
+ (when style
+ (princ "</span>" buffer))))))
;;; `font' tag based output support.
@@ -1390,7 +1562,7 @@ it's called with the same value of KEY. All other times, the cached
(htmlize-fstruct-foreground fstruct)
(htmlize-fstruct-background fstruct))))
-(defun htmlize-font-insert-text (text fstruct-list buffer)
+(defun htmlize-font-text-markup (fstruct-list buffer)
;; In `font' mode, we use the traditional HTML means of altering
;; presentation: <font> tag for colors, <b> for bold, <u> for
;; underline, and <strike> for strike-through.
@@ -1411,8 +1583,9 @@ it's called with the same value of KEY. All other times, the cached
(and (htmlize-fstruct-boldp merged) "</b>")
(and (htmlize-fstruct-foreground merged) "</font>"))))))
(princ (car markup) buffer)
- (princ text buffer)
- (princ (cdr markup) buffer)))
+ (htmlize-lexlet ((markup markup) (buffer buffer))
+ (lambda ()
+ (princ (cdr markup) buffer)))))
(defun htmlize-buffer-1 ()
;; Internal function; don't call it from outside this file. Htmlize
@@ -1428,122 +1601,118 @@ it's called with the same value of KEY. All other times, the cached
(htmlize-ensure-fontified)
(clrhash htmlize-extended-character-cache)
(clrhash htmlize-memoization-table)
- (let* ((buffer-faces (htmlize-faces-in-buffer))
- (face-map (htmlize-make-face-map (adjoin 'default buffer-faces)))
- ;; Generate the new buffer. It's important that it inherits
- ;; default-directory from the current buffer.
- (htmlbuf (generate-new-buffer (if (buffer-file-name)
- (htmlize-make-file-name
- (file-name-nondirectory
- (buffer-file-name)))
- "*html*")))
- ;; Having a dummy value in the plist allows writing simply
- ;; (plist-put places foo bar).
- (places '(nil nil))
- (title (if (buffer-file-name)
- (file-name-nondirectory (buffer-file-name))
- (buffer-name))))
- ;; Initialize HTMLBUF and insert the HTML prolog.
- (with-current-buffer htmlbuf
- (buffer-disable-undo)
- (insert (htmlize-method doctype) ?\n
- (format "<!-- Created by htmlize-%s in %s mode. -->\n"
- htmlize-version htmlize-output-type)
- "<html>\n ")
- (plist-put places 'head-start (point-marker))
- (insert "<head>\n"
- " <title>" (htmlize-protect-string title) "</title>\n"
- (if htmlize-html-charset
- (format (concat " <meta http-equiv=\"Content-Type\" "
- "content=\"text/html; charset=%s\">\n")
- htmlize-html-charset)
- "")
- htmlize-head-tags)
- (htmlize-method insert-head buffer-faces face-map)
- (insert " </head>")
- (plist-put places 'head-end (point-marker))
- (insert "\n ")
- (plist-put places 'body-start (point-marker))
- (insert (htmlize-method body-tag face-map)
- "\n ")
- (plist-put places 'content-start (point-marker))
- (insert "<pre>\n"))
- (let ((insert-text-method
- ;; Get the inserter method, so we can funcall it inside
- ;; the loop. Not calling `htmlize-method' in the loop
- ;; body yields a measurable speed increase.
- (htmlize-method-function 'insert-text))
- ;; Declare variables used in loop body outside the loop
- ;; because it's faster to establish `let' bindings only
- ;; once.
- next-change text face-list fstruct-list trailing-ellipsis)
- ;; This loop traverses and reads the source buffer, appending
- ;; the resulting HTML to HTMLBUF with `princ'. This method is
- ;; fast because: 1) it doesn't require examining the text
- ;; properties char by char (htmlize-next-change is used to
- ;; move between runs with the same face), and 2) it doesn't
- ;; require buffer switches, which are slow in Emacs.
- (goto-char (point-min))
- (while (not (eobp))
- (setq next-change (htmlize-next-change (point) 'face))
- ;; Get faces in use between (point) and NEXT-CHANGE, and
- ;; convert them to fstructs.
- (setq face-list (htmlize-faces-at-point)
- fstruct-list (delq nil (mapcar (lambda (f)
- (gethash f face-map))
- face-list)))
- ;; Extract buffer text, sans the invisible parts. Then
- ;; untabify it and escape the HTML metacharacters.
- (setq text (htmlize-buffer-substring-no-invisible
- (point) next-change))
- (when trailing-ellipsis
- (setq text (htmlize-trim-ellipsis text)))
- ;; If TEXT ends up empty, don't change trailing-ellipsis.
- (when (> (length text) 0)
- (setq trailing-ellipsis
- (get-text-property (1- (length text))
- 'htmlize-ellipsis text)))
- (setq text (htmlize-untabify text (current-column)))
- (setq text (htmlize-protect-string text))
- ;; Don't bother writing anything if there's no text (this
- ;; happens in invisible regions).
- (when (> (length text) 0)
- ;; Insert the text, along with the necessary markup to
- ;; represent faces in FSTRUCT-LIST.
- (funcall insert-text-method text fstruct-list htmlbuf))
- (goto-char next-change)))
-
- ;; Insert the epilog and post-process the buffer.
- (with-current-buffer htmlbuf
- (insert "</pre>")
- (plist-put places 'content-end (point-marker))
- (insert "\n </body>")
- (plist-put places 'body-end (point-marker))
- (insert "\n</html>\n")
- (when htmlize-generate-hyperlinks
- (htmlize-make-hyperlinks))
- (htmlize-defang-local-variables)
- (when htmlize-replace-form-feeds
- ;; Change each "\n^L" to "<hr />".
- (goto-char (point-min))
- (let ((source
- ;; ^L has already been escaped, so search for that.
- (htmlize-protect-string "\n\^L"))
- (replacement
- (if (stringp htmlize-replace-form-feeds)
- htmlize-replace-form-feeds
- "</pre><hr /><pre>")))
- (while (search-forward source nil t)
- (replace-match replacement t t))))
- (goto-char (point-min))
- (when htmlize-html-major-mode
- ;; What sucks about this is that the minor modes, most notably
- ;; font-lock-mode, won't be initialized. Oh well.
- (funcall htmlize-html-major-mode))
- (set (make-local-variable 'htmlize-buffer-places) places)
- (run-hooks 'htmlize-after-hook)
- (buffer-enable-undo))
- htmlbuf)))
+ ;; It's important that the new buffer inherits default-directory
+ ;; from the current buffer.
+ (let ((htmlbuf (generate-new-buffer (if (buffer-file-name)
+ (htmlize-make-file-name
+ (file-name-nondirectory
+ (buffer-file-name)))
+ "*html*")))
+ (completed nil))
+ (unwind-protect
+ (let* ((buffer-faces (htmlize-faces-in-buffer))
+ (face-map (htmlize-make-face-map (adjoin 'default buffer-faces)))
+ (places (gensym))
+ (title (if (buffer-file-name)
+ (file-name-nondirectory (buffer-file-name))
+ (buffer-name))))
+ (when htmlize-generate-hyperlinks
+ (htmlize-create-auto-links))
+ (when htmlize-replace-form-feeds
+ (htmlize-shadow-form-feeds))
+
+ ;; Initialize HTMLBUF and insert the HTML prolog.
+ (with-current-buffer htmlbuf
+ (buffer-disable-undo)
+ (insert (htmlize-method doctype) ?\n
+ (format "<!-- Created by htmlize-%s in %s mode. -->\n"
+ htmlize-version htmlize-output-type)
+ "<html>\n ")
+ (put places 'head-start (point-marker))
+ (insert "<head>\n"
+ " <title>" (htmlize-protect-string title) "</title>\n"
+ (if htmlize-html-charset
+ (format (concat " <meta http-equiv=\"Content-Type\" "
+ "content=\"text/html; charset=%s\">\n")
+ htmlize-html-charset)
+ "")
+ htmlize-head-tags)
+ (htmlize-method insert-head buffer-faces face-map)
+ (insert " </head>")
+ (put places 'head-end (point-marker))
+ (insert "\n ")
+ (put places 'body-start (point-marker))
+ (insert (htmlize-method body-tag face-map)
+ "\n ")
+ (put places 'content-start (point-marker))
+ (insert "<pre>\n"))
+ (let ((text-markup
+ ;; Get the inserter method, so we can funcall it inside
+ ;; the loop. Not calling `htmlize-method' in the loop
+ ;; body yields a measurable speed increase.
+ (htmlize-method-function 'text-markup))
+ ;; Declare variables used in loop body outside the loop
+ ;; because it's faster to establish `let' bindings only
+ ;; once.
+ next-change text face-list trailing-ellipsis
+ fstruct-list last-fstruct-list
+ (close-markup (lambda ())))
+ ;; This loop traverses and reads the source buffer, appending
+ ;; the resulting HTML to HTMLBUF. This method is fast
+ ;; because: 1) it doesn't require examining the text
+ ;; properties char by char (htmlize-next-face-change is used
+ ;; to move between runs with the same face), and 2) it doesn't
+ ;; require frequent buffer switches, which are slow because
+ ;; they rebind all buffer-local vars.
+ (goto-char (point-min))
+ (while (not (eobp))
+ (setq next-change (htmlize-next-face-change (point)))
+ ;; Get faces in use between (point) and NEXT-CHANGE, and
+ ;; convert them to fstructs.
+ (setq face-list (htmlize-faces-at-point)
+ fstruct-list (delq nil (mapcar (lambda (f)
+ (gethash f face-map))
+ face-list)))
+ (multiple-value-setq (text trailing-ellipsis)
+ (htmlize-extract-text (point) next-change trailing-ellipsis))
+ ;; Don't bother writing anything if there's no text (this
+ ;; happens in invisible regions).
+ (when (> (length text) 0)
+ ;; Open the new markup if necessary and insert the text.
+ (when (not (equalp fstruct-list last-fstruct-list))
+ (funcall close-markup)
+ (setq last-fstruct-list fstruct-list
+ close-markup (funcall text-markup fstruct-list htmlbuf)))
+ (princ text htmlbuf))
+ (goto-char next-change))
+
+ ;; We've gone through the buffer; close the markup from
+ ;; the last run, if any.
+ (funcall close-markup))
+
+ ;; Insert the epilog and post-process the buffer.
+ (with-current-buffer htmlbuf
+ (insert "</pre>")
+ (put places 'content-end (point-marker))
+ (insert "\n </body>")
+ (put places 'body-end (point-marker))
+ (insert "\n</html>\n")
+ (htmlize-defang-local-variables)
+ (goto-char (point-min))
+ (when htmlize-html-major-mode
+ ;; What sucks about this is that the minor modes, most notably
+ ;; font-lock-mode, won't be initialized. Oh well.
+ (funcall htmlize-html-major-mode))
+ (set (make-local-variable 'htmlize-buffer-places)
+ (symbol-plist places))
+ (run-hooks 'htmlize-after-hook)
+ (buffer-enable-undo))
+ (setq completed t)
+ htmlbuf)
+
+ (when (not completed)
+ (kill-buffer htmlbuf))
+ (htmlize-delete-tmp-overlays)))))
;; Utility functions.
@@ -1766,4 +1935,9 @@ corresponding source file."
(provide 'htmlize)
+;; Local Variables:
+;; byte-compile-warnings: (not cl-functions lexical unresolved obsolete)
+;; lexical-binding: t
+;; End:
+
;;; htmlize.el ends here
diff --git a/contrib/lisp/ob-eukleides.el b/contrib/lisp/ob-eukleides.el
new file mode 100644
index 0000000..e25ed1c
--- /dev/null
+++ b/contrib/lisp/ob-eukleides.el
@@ -0,0 +1,98 @@
+;;; ob-eukleides.el --- Org-babel functions for eukleides evaluation
+
+;; Copyright (C) 2010-2013 Free Software Foundation, Inc.
+
+;; Author: Luis Anaya
+;; Keywords: literate programming, reproducible research
+;; Homepage: http://orgmode.org
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Org-Babel support for evaluating eukleides script.
+;;
+;; Inspired by Ian Yang's org-export-blocks-format-eukleides
+;; http://www.emacswiki.org/emacs/org-export-blocks-format-eukleides.el
+
+;;; Requirements:
+
+;; eukleides | http://eukleides.org
+;; eukleides | `org-eukleides-path' should point to the eukleides executablexs
+
+;;; Code:
+(require 'ob)
+(require 'ob-eval)
+
+(defvar org-babel-default-header-args:eukleides
+ '((:results . "file") (:exports . "results"))
+ "Default arguments for evaluating a eukleides source block.")
+
+(defcustom org-eukleides-path nil
+ "Path to the eukleides executable file."
+ :group 'org-babel
+ :type 'string)
+
+(defcustom org-eukleides-eps-to-raster nil
+ "Command used to convert EPS to raster. Nil for no conversion."
+ :group 'org-babel
+ :type '(choice
+ (repeat :tag "Shell Command Sequence" (string :tag "Shell Command"))
+ (const :tag "sam2p" "a=%s;b=%s;sam2p ${a} ${b}" )
+ (const :tag "NetPNM" "a=%s;b=%s;pstopnm -stdout ${a} | pnmtopng > ${b}" )
+ (const :tag "None" nil)))
+
+(defun org-babel-execute:eukleides (body params)
+ "Execute a block of eukleides code with org-babel.
+This function is called by `org-babel-execute-src-block'."
+ (let* ((result-params (split-string (or (cdr (assoc :results params)) "")))
+ (out-file (or (cdr (assoc :file params))
+ (error "Eukleides requires a \":file\" header argument")))
+ (cmdline (cdr (assoc :cmdline params)))
+ (in-file (org-babel-temp-file "eukleides-"))
+ (java (or (cdr (assoc :java params)) ""))
+ (cmd (if (not org-eukleides-path)
+ (error "`org-eukleides-path' is not set")
+ (concat (expand-file-name org-eukleides-path)
+ " -b --output="
+ (org-babel-process-file-name
+ (concat
+ (file-name-sans-extension out-file) ".eps"))
+ " "
+ (org-babel-process-file-name in-file)))))
+ (unless (file-exists-p org-eukleides-path)
+ (error "Could not find eukleides at %s" org-eukleides-path))
+
+ (if (string= (file-name-extension out-file) "png")
+ (if org-eukleides-eps-to-raster
+ (shell-command (format org-eukleides-eps-to-raster
+ (concat (file-name-sans-extension out-file) ".eps")
+ (concat (file-name-sans-extension out-file) ".png")))
+ (error "Conversion to PNG not supported. use a file with an EPS name")))
+
+ (with-temp-file in-file (insert body))
+ (message "%s" cmd) (org-babel-eval cmd "")
+ nil)) ;; signal that output has already been written to file
+
+(defun org-babel-prep-session:eukleides (session params)
+ "Return an error because eukleides does not support sessions."
+ (error "Eukleides does not support sessions"))
+
+(provide 'ob-eukleides)
+
+
+
+;;; ob-eukleides.el ends here
diff --git a/contrib/babel/langs/ob-fomus.el b/contrib/lisp/ob-fomus.el
index f7c6ca8..58183fb 100644
--- a/contrib/babel/langs/ob-fomus.el
+++ b/contrib/lisp/ob-fomus.el
@@ -1,13 +1,12 @@
-;;; ob-fomus.el --- org-babel functions for fomus evaluation
+;;; ob-fomus.el --- Org-babel functions for fomus evaluation
-;; Copyright (C) 2011-2012 Torsten Anders
+;; Copyright (C) 2011-2013 Torsten Anders
;; Author: Torsten Anders
;; Keywords: literate programming, reproducible research
;; Homepage: http://orgmode.org
-;; Version:
-;;; License:
+;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
diff --git a/contrib/lisp/ob-julia.el b/contrib/lisp/ob-julia.el
new file mode 100644
index 0000000..3aed818
--- /dev/null
+++ b/contrib/lisp/ob-julia.el
@@ -0,0 +1,302 @@
+;;; ob-julia.el --- org-babel functions for julia code evaluation
+
+;; Copyright (C) 2013 G. Jay Kerns
+;; Author: G. Jay Kerns, based on ob-R.el by Eric Schulte and Dan Davison
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, 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 GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
+
+;; The file provides Org-Babel support for evaluating julia code.
+;;
+;; See https://github.com/gjkerns/ob-julia/blob/master/ob-julia-doc.org
+;; for detailed instructions on how to get started. The git repository
+;; contains more documentation: git://github.com/gjkerns/ob-julia.git
+
+;;; Code:
+(require 'ob)
+(eval-when-compile (require 'cl))
+
+(declare-function orgtbl-to-csv "org-table" (table params))
+(declare-function julia "ext:ess-julia" (&optional start-args))
+(declare-function inferior-ess-send-input "ext:ess-inf" ())
+(declare-function ess-make-buffer-current "ext:ess-inf" ())
+(declare-function ess-eval-buffer "ext:ess-inf" (vis))
+(declare-function org-number-sequence "org-compat" (from &optional to inc))
+(declare-function org-remove-if-not "org" (predicate seq))
+
+(defconst org-babel-header-args:julia
+ '((width . :any)
+ (horizontal . :any)
+ (results . ((file list vector table scalar verbatim)
+ (raw org html latex code pp wrap)
+ (replace silent append prepend)
+ (output value graphics))))
+ "julia-specific header arguments.")
+
+(add-to-list 'org-babel-tangle-lang-exts '("julia" . "jl"))
+
+(defvar org-babel-default-header-args:julia '())
+
+(defcustom org-babel-julia-command inferior-julia-program-name
+ "Name of command to use for executing julia code."
+ :group 'org-babel
+ :version "24.4"
+ :package-version '(Org . "8.0")
+ :type 'string)
+
+(defvar ess-local-process-name) ; dynamically scoped
+(defun org-babel-edit-prep:julia (info)
+ (let ((session (cdr (assoc :session (nth 2 info)))))
+ (when (and session (string-match "^\\*\\(.+?\\)\\*$" session))
+ (save-match-data (org-babel-julia-initiate-session session nil)))))
+
+(defun org-babel-expand-body:julia (body params &optional graphics-file)
+ "Expand BODY according to PARAMS, return the expanded body."
+ (let ((graphics-file
+ (or graphics-file (org-babel-julia-graphical-output-file params))))
+ (mapconcat
+ #'identity
+ ((lambda (inside)
+ (if graphics-file
+ inside
+ inside))
+ (append (org-babel-variable-assignments:julia params)
+ (list body))) "\n")))
+
+(defun org-babel-execute:julia (body params)
+ "Execute a block of julia code.
+This function is called by `org-babel-execute-src-block'."
+ (save-excursion
+ (let* ((result-params (cdr (assoc :result-params params)))
+ (result-type (cdr (assoc :result-type params)))
+ (session (org-babel-julia-initiate-session
+ (cdr (assoc :session params)) params))
+ (colnames-p (cdr (assoc :colnames params)))
+ (rownames-p (cdr (assoc :rownames params)))
+ (graphics-file (org-babel-julia-graphical-output-file params))
+ (full-body (org-babel-expand-body:julia body params graphics-file))
+ (result
+ (org-babel-julia-evaluate
+ session full-body result-type result-params
+ (or (equal "yes" colnames-p)
+ (org-babel-pick-name
+ (cdr (assoc :colname-names params)) colnames-p))
+ (or (equal "yes" rownames-p)
+ (org-babel-pick-name
+ (cdr (assoc :rowname-names params)) rownames-p)))))
+ (if graphics-file nil result))))
+
+(defun org-babel-prep-session:julia (session params)
+ "Prepare SESSION according to the header arguments specified in PARAMS."
+ (let* ((session (org-babel-julia-initiate-session session params))
+ (var-lines (org-babel-variable-assignments:julia params)))
+ (org-babel-comint-in-buffer session
+ (mapc (lambda (var)
+ (end-of-line 1) (insert var) (comint-send-input nil t)
+ (org-babel-comint-wait-for-output session)) var-lines))
+ session))
+
+(defun org-babel-load-session:julia (session body params)
+ "Load BODY into SESSION."
+ (save-window-excursion
+ (let ((buffer (org-babel-prep-session:julia session params)))
+ (with-current-buffer buffer
+ (goto-char (process-mark (get-buffer-process (current-buffer))))
+ (insert (org-babel-chomp body)))
+ buffer)))
+
+;; helper functions
+
+(defun org-babel-variable-assignments:julia (params)
+ "Return list of julia statements assigning the block's variables."
+ (let ((vars (mapcar #'cdr (org-babel-get-header params :var))))
+ (mapcar
+ (lambda (pair)
+ (org-babel-julia-assign-elisp
+ (car pair) (cdr pair)
+ (equal "yes" (cdr (assoc :colnames params)))
+ (equal "yes" (cdr (assoc :rownames params)))))
+ (mapcar
+ (lambda (i)
+ (cons (car (nth i vars))
+ (org-babel-reassemble-table
+ (cdr (nth i vars))
+ (cdr (nth i (cdr (assoc :colname-names params))))
+ (cdr (nth i (cdr (assoc :rowname-names params)))))))
+ (org-number-sequence 0 (1- (length vars)))))))
+
+(defun org-babel-julia-quote-csv-field (s)
+ "Quote field S for export to julia."
+ (if (stringp s)
+ (concat "\"" (mapconcat 'identity (split-string s "\"") "\"\"") "\"")
+ (format "%S" s)))
+
+(defun org-babel-julia-assign-elisp (name value colnames-p rownames-p)
+ "Construct julia code assigning the elisp VALUE to a variable named NAME."
+ (if (listp value)
+ (let ((max (apply #'max (mapcar #'length (org-remove-if-not
+ #'sequencep value))))
+ (min (apply #'min (mapcar #'length (org-remove-if-not
+ #'sequencep value))))
+ (transition-file (org-babel-temp-file "julia-import-")))
+ ;; ensure VALUE has an orgtbl structure (depth of at least 2)
+ (unless (listp (car value)) (setq value (list value)))
+ (with-temp-file transition-file
+ (insert
+ (orgtbl-to-csv value '(:fmt org-babel-julia-quote-csv-field))
+ "\n"))
+ (let ((file (org-babel-process-file-name transition-file 'noquote))
+ (header (if (or (eq (nth 1 value) 'hline) colnames-p)
+ "TRUE" "FALSE"))
+ (row-names (if rownames-p "1" "NULL")))
+ (if (= max min)
+ (format "%s = readcsv(\"%s\")" name file)
+ (format "%s = readcsv(\"%s\")"
+ name file))))
+ (format "%s = %s" name (org-babel-julia-quote-csv-field value))))
+
+(defvar ess-ask-for-ess-directory) ; dynamically scoped
+
+(defun org-babel-julia-initiate-session (session params)
+ "If there is not a current julia process then create one."
+ (unless (string= session "none")
+ (let ((session (or session "*julia*"))
+ (ess-ask-for-ess-directory
+ (and (and (boundp 'ess-ask-for-ess-directory) ess-ask-for-ess-directory)
+ (not (cdr (assoc :dir params))))))
+ (if (org-babel-comint-buffer-livep session)
+ session
+ (save-window-excursion
+ (require 'ess) (julia)
+ (rename-buffer
+ (if (bufferp session)
+ (buffer-name session)
+ (if (stringp session)
+ session
+ (buffer-name))))
+ (current-buffer))))))
+
+(defun org-babel-julia-associate-session (session)
+ "Associate julia code buffer with a julia session.
+Make SESSION be the inferior ESS process associated with the
+current code buffer."
+ (setq ess-local-process-name
+ (process-name (get-buffer-process session)))
+ (ess-make-buffer-current))
+
+(defun org-babel-julia-graphical-output-file (params)
+ "Name of file to which julia should send graphical output."
+ (and (member "graphics" (cdr (assq :result-params params)))
+ (cdr (assq :file params))))
+
+(defvar org-babel-julia-eoe-indicator "print(\"org_babel_julia_eoe\")")
+(defvar org-babel-julia-eoe-output "org_babel_julia_eoe")
+
+(defvar org-babel-julia-write-object-command "writecsv(\"%s\",%s)")
+
+;; The following was a very complicated write object command
+;; The replacement needs to add error catching
+;(defvar org-babel-julia-write-object-command "{function(object,transfer.file){object;invisible(if(inherits(try({tfile<-tempfile();write.table(object,file=tfile,sep=\"\\t\",na=\"nil\",row.names=%s,col.names=%s,quote=FALSE);file.rename(tfile,transfer.file)},silent=TRUE),\"try-error\")){if(!file.exists(transfer.file))file.create(transfer.file)})}}(object=%s,transfer.file=\"%s\")")
+
+(defun org-babel-julia-evaluate
+ (session body result-type result-params column-names-p row-names-p)
+ "Evaluate julia code in BODY."
+ (if session
+ (org-babel-julia-evaluate-session
+ session body result-type result-params column-names-p row-names-p)
+ (org-babel-julia-evaluate-external-process
+ body result-type result-params column-names-p row-names-p)))
+
+(defun org-babel-julia-evaluate-external-process
+ (body result-type result-params column-names-p row-names-p)
+ "Evaluate BODY in external julia process.
+If RESULT-TYPE equals 'output then return standard output as a
+string. If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+ (case result-type
+ (value
+ (let ((tmp-file (org-babel-temp-file "julia-")))
+ (org-babel-eval org-babel-julia-command
+ (format org-babel-julia-write-object-command
+ (org-babel-process-file-name tmp-file 'noquote)
+ (format "begin\n%s\nend" body)))
+ (org-babel-julia-process-value-result
+ (org-babel-result-cond result-params
+ (with-temp-buffer
+ (insert-file-contents tmp-file)
+ (buffer-string))
+ (org-babel-import-elisp-from-file tmp-file '(4)))
+ column-names-p)))
+ (output (org-babel-eval org-babel-julia-command body))))
+
+(defun org-babel-julia-evaluate-session
+ (session body result-type result-params column-names-p row-names-p)
+ "Evaluate BODY in SESSION.
+If RESULT-TYPE equals 'output then return standard output as a
+string. If RESULT-TYPE equals 'value then return the value of the
+last statement in BODY, as elisp."
+ (case result-type
+ (value
+ (with-temp-buffer
+ (insert (org-babel-chomp body))
+ (let ((ess-local-process-name
+ (process-name (get-buffer-process session)))
+ (ess-eval-visibly-p nil))
+ (ess-eval-buffer nil)))
+ (let ((tmp-file (org-babel-temp-file "julia-")))
+ (org-babel-comint-eval-invisibly-and-wait-for-file
+ session tmp-file
+ (format org-babel-julia-write-object-command
+ (org-babel-process-file-name tmp-file 'noquote) "ans"))
+ (org-babel-julia-process-value-result
+ (org-babel-result-cond result-params
+ (with-temp-buffer
+ (insert-file-contents tmp-file)
+ (buffer-string))
+ (org-babel-import-elisp-from-file tmp-file '(4)))
+ column-names-p)))
+ (output
+ (mapconcat
+ #'org-babel-chomp
+ (butlast
+ (delq nil
+ (mapcar
+ (lambda (line) (when (> (length line) 0) line))
+ (mapcar
+ (lambda (line) ;; cleanup extra prompts left in output
+ (if (string-match
+ "^\\([ ]*[>+\\.][ ]?\\)+\\([[0-9]+\\|[ ]\\)" line)
+ (substring line (match-end 1))
+ line))
+ (org-babel-comint-with-output (session org-babel-julia-eoe-output)
+ (insert (mapconcat #'org-babel-chomp
+ (list body org-babel-julia-eoe-indicator)
+ "\n"))
+ (inferior-ess-send-input)))))) "\n"))))
+
+(defun org-babel-julia-process-value-result (result column-names-p)
+ "julia-specific processing of return value.
+Insert hline if column names in output have been requested."
+ (if column-names-p
+ (cons (car result) (cons 'hline (cdr result)))
+ result))
+
+(provide 'ob-julia)
+
+;;; ob-julia.el ends here
diff --git a/contrib/lisp/ob-mathomatic.el b/contrib/lisp/ob-mathomatic.el
new file mode 100644
index 0000000..585604e
--- /dev/null
+++ b/contrib/lisp/ob-mathomatic.el
@@ -0,0 +1,145 @@
+;;; ob-mathomatic.el --- Org-babel functions for mathomatic evaluation
+
+;; Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+;; Author: Eric S Fraga
+;; Eric Schulte
+;; Luis Anaya (Mathomatic)
+
+;; Keywords: literate programming, reproducible research, mathomatic
+;; Homepage: http://orgmode.org
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Org-Babel support for evaluating mathomatic entries.
+;;
+;; This differs from most standard languages in that
+;;
+;; 1) there is no such thing as a "session" in mathomatic
+;;
+;; 2) we are adding the "cmdline" header argument
+
+;;; Code:
+(require 'ob)
+
+(defvar org-babel-tangle-lang-exts)
+(add-to-list 'org-babel-tangle-lang-exts '("mathomatic" . "math"))
+
+(defvar org-babel-default-header-args:mathomatic '())
+
+(defcustom org-babel-mathomatic-command
+ (if (boundp 'mathomatic-command) mathomatic-command "mathomatic")
+ "Command used to call mathomatic on the shell."
+ :group 'org-babel)
+
+(defun org-babel-mathomatic-expand (body params)
+ "Expand a block of Mathomatic code according to its header arguments."
+ (let ((vars (mapcar #'cdr (org-babel-get-header params :var))))
+ (mapconcat 'identity
+ (list
+ ;; graphic output
+ (let ((graphic-file (org-babel-mathomatic-graphical-output-file params)))
+ (if graphic-file
+ (cond
+ ((string-match ".\.eps$" graphic-file)
+ (format ;; Need to add command to send to file.
+ "set plot set terminal postscript eps\\;set output %S "
+ graphic-file))
+ ((string-match ".\.ps$" graphic-file)
+ (format ;; Need to add command to send to file.
+ "set plot set terminal postscript\\;set output %S "
+ graphic-file))
+
+ ((string-match ".\.pic$" graphic-file)
+ (format ;; Need to add command to send to file.
+ "set plot set terminal gpic\\;set output %S "
+ graphic-file))
+ (t
+ (format ;; Need to add command to send to file.
+ "set plot set terminal png\\;set output %S "
+ graphic-file)))
+ ""))
+ ;; variables
+ (mapconcat 'org-babel-mathomatic-var-to-mathomatic vars "\n")
+ ;; body
+ body
+ "")
+ "\n")))
+
+(defun org-babel-execute:mathomatic (body params)
+ "Execute a block of Mathomatic entries with org-babel. This function is
+called by `org-babel-execute-src-block'."
+ (message "executing Mathomatic source code block")
+ (let ((result-params (split-string (or (cdr (assoc :results params)) "")))
+ (result
+ (let* ((cmdline (or (cdr (assoc :cmdline params)) ""))
+ (in-file (org-babel-temp-file "mathomatic-" ".math"))
+ (cmd (format "%s -t -c -q %s %s"
+ org-babel-mathomatic-command in-file cmdline)))
+ (with-temp-file in-file (insert (org-babel-mathomatic-expand body params)))
+ (message cmd)
+ ((lambda (raw) ;; " | grep -v batch | grep -v 'replaced' | sed '/^$/d' "
+ (mapconcat
+ #'identity
+ (delq nil
+ (mapcar (lambda (line)
+ (unless (or (string-match "batch" line)
+ (string-match "^rat: replaced .*$" line)
+ (= 0 (length line)))
+ line))
+ (split-string raw "[\r\n]"))) "\n"))
+ (org-babel-eval cmd "")))))
+ (if (org-babel-mathomatic-graphical-output-file params)
+ nil
+ (if (or (member "scalar" result-params)
+ (member "verbatim" result-params)
+ (member "output" result-params))
+ result
+ (let ((tmp-file (org-babel-temp-file "mathomatic-res-")))
+ (with-temp-file tmp-file (insert result))
+ (org-babel-import-elisp-from-file tmp-file))))))
+
+(defun org-babel-prep-session:mathomatic (session params)
+ (error "Mathomatic does not support sessions"))
+
+(defun org-babel-mathomatic-var-to-mathomatic (pair)
+ "Convert an elisp val into a string of mathomatic code specifying a var
+of the same value."
+ (let ((var (car pair))
+ (val (cdr pair)))
+ (when (symbolp val)
+ (setq val (symbol-name val))
+ (when (= (length val) 1)
+ (setq val (string-to-char val))))
+ (format "%s=%s" var
+ (org-babel-mathomatic-elisp-to-mathomatic val))))
+
+(defun org-babel-mathomatic-graphical-output-file (params)
+ "Name of file to which mathomatic should send graphical output."
+ (and (member "graphics" (cdr (assq :result-params params)))
+ (cdr (assq :file params))))
+
+(defun org-babel-mathomatic-elisp-to-mathomatic (val)
+ "Return a string of mathomatic code which evaluates to VAL."
+ (if (listp val)
+ (mapconcat #'org-babel-mathomatic-elisp-to-mathomatic val " ")
+ (format "%s" val)))
+
+(provide 'ob-mathomatic)
+
+;;; ob-mathomatic.el ends here
diff --git a/contrib/babel/langs/ob-oz.el b/contrib/lisp/ob-oz.el
index b778b4a..ce8e8a6 100644
--- a/contrib/babel/langs/ob-oz.el
+++ b/contrib/lisp/ob-oz.el
@@ -1,13 +1,13 @@
-;;; ob-oz.el --- org-babel functions for Oz evaluation
+;;; ob-oz.el --- Org-babel functions for Oz evaluation
-;; Copyright (C) 2009-2012 Torsten Anders and Eric Schulte
+;; Copyright (C) 2009-2013 Torsten Anders and Eric Schulte
-;; Author: Torsten Anders and Eric Schulte
+;; Author: Torsten Anders and Eric Schulte
;; Keywords: literate programming, reproducible research
;; Homepage: http://orgmode.org
;; Version: 0.02
-;;; License:
+;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@
;;; Commentary:
-;; Org-Babel support for evaluating Oz source code.
+;; Org-Babel support for evaluating Oz source code.
;;
;; Oz code is always send to the Oz Programming Environment (OPI), the
;; Emacs mode and compiler interface for Oz programs. Therefore, only
@@ -71,7 +71,7 @@
;; arrive then in any order) I could use IDs
;; (e.g. integers). However, how do I do concurrency in Emacs Lisp,
;; and how can I define org-babel-execute:oz concurrently.
-;;
+;;
;; - Expressions are rarely used in Oz at the top-level, and using
;; them in documentation and Literate Programs will cause
;; confusion. Idea: hide expression from reader and instead show
@@ -94,10 +94,10 @@
;;
;; Interface to communicate with Oz.
-;; (1) For statements without any results: oz-send-string
+;; (1) For statements without any results: oz-send-string
;; (2) For expressions with a single result: oz-send-string-expression
;; (defined in org-babel-oz-ResultsValue.el)
-;;
+;;
;; oz-send-string-expression implements an additional very direct
;; communication between Org-babel and the Oz compiler. Communication
@@ -128,7 +128,7 @@
"Path to the contrib/scripts directory in which
StartOzServer.oz is located.")
-(defvar org-babel-oz-port 6001
+(defvar org-babel-oz-port 6001
"Port for communicating with Oz compiler.")
(defvar org-babel-oz-OPI-socket nil
"Socket for communicating with OPI.")
@@ -144,18 +144,18 @@ StartOzServer.oz is located.")
(defun org-babel-oz-create-socket ()
(message "Create OPI socket for evaluating expressions")
- ;; Start Oz directly
+ ;; Start Oz directly
(run-oz)
;; Create socket on Oz side (after Oz was started).
(oz-send-string (concat "\\insert '" org-babel-oz-server-dir "StartOzServer.oz'"))
;; Wait until socket is created before connecting to it.
;; Quick hack: wait 3 sec
- ;;
+ ;;
;; extending time to 30 secs does not help when starting Emacs for
;; the first time (and computer does nothing else)
(sit-for 3)
;; connect to OPI socket
- (setq org-babel-oz-OPI-socket
+ (setq org-babel-oz-OPI-socket
;; Creates a socket. I/O interface of Emacs sockets as for processes.
(open-network-stream "*Org-babel-OPI-socket*" nil "localhost" org-babel-oz-port))
;; install filter
@@ -166,7 +166,7 @@ StartOzServer.oz is located.")
;; oz-send-string-expression turns is into synchronous...
(defun oz-send-string-expression (string &optional wait-time)
"Similar to oz-send-string, oz-send-string-expression sends a string to the OPI compiler. However, string must be expression and this function returns the result of the expression (as string). oz-send-string-expression is synchronous, wait-time allows to specify a maximum wait time. After wait-time is over with no result, the function returns nil."
- (if (not org-babel-oz-OPI-socket)
+ (if (not org-babel-oz-OPI-socket)
(org-babel-oz-create-socket))
(let ((polling-delay 0.1)
result)
@@ -176,11 +176,11 @@ StartOzServer.oz is located.")
(let ((waited 0))
(unwind-protect
(progn
- (while
+ (while
;; stop loop if org-babel-oz-collected-result \= nil or waiting time is over
(not (or (not (equal org-babel-oz-collected-result nil))
(> waited wait-time)))
- (progn
+ (progn
(sit-for polling-delay)
;; (message "org-babel-oz: next polling iteration")
(setq waited (+ waited polling-delay))))
@@ -253,7 +253,7 @@ called by `org-babel-execute-src-block' via multiple-value-bind."
;; (when vars
;; (with-temp-buffer
;; (insert var-lines) (write-file vars-file)
-;; (oz-mode)
+;; (oz-mode)
;; ;; (inferior-oz-load-file) ; ??
;; ))
;; (current-buffer))))
@@ -262,7 +262,7 @@ called by `org-babel-execute-src-block' via multiple-value-bind."
;; TODO: testing... (simplified version of def in org-babel-prep-session:ocaml)
;;
-;; BUG: does not work yet. Error: ad-Orig-error: buffer none doesn't exist or has no process
+;; BUG: does not work yet. Error: ad-Orig-error: buffer none doesn't exist or has no process
;; UNUSED DEF
(defun org-babel-oz-initiate-session (&optional session params)
"If there is not a current inferior-process-buffer in SESSION
@@ -278,12 +278,12 @@ then create. Return the initialized session."
specifying a var of the same value."
(if (listp var)
;; (concat "[" (mapconcat #'org-babel-oz-var-to-oz var ", ") "]")
- (eval var)
- (format "%s" var) ; don't preserve string quotes.
+ (eval var)
+ (format "%s" var) ; don't preserve string quotes.
;; (format "%s" var)
))
-;; TODO:
+;; TODO:
(defun org-babel-oz-table-or-string (results)
"If the results look like a table, then convert them into an
Emacs-lisp table, otherwise return the results as a string."
diff --git a/contrib/lisp/ob-tcl.el b/contrib/lisp/ob-tcl.el
new file mode 100644
index 0000000..e8d735b
--- /dev/null
+++ b/contrib/lisp/ob-tcl.el
@@ -0,0 +1,128 @@
+;;; ob-tcl.el --- Org-babel functions for tcl evaluation
+
+;; Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+;; Authors: Dan Davison
+;; Eric Schulte
+;; Luis Anaya (tcl)
+;;
+;; Keywords: literate programming, reproducible research
+;; Homepage: http://orgmode.org
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Org-Babel support for evaluating tcl source code.
+
+;;; Code:
+(require 'ob)
+(require 'ob-eval)
+(eval-when-compile (require 'cl))
+
+(defvar org-babel-tangle-lang-exts)
+(add-to-list 'org-babel-tangle-lang-exts '("tcl" . "tcl"))
+
+(defvar org-babel-default-header-args:tcl nil)
+
+(defcustom org-babel-tcl-command "tclsh"
+"Name of command to use for executing Tcl code."
+ :group 'org-babel
+ :type 'string)
+
+
+(defun org-babel-execute:tcl (body params)
+ "Execute a block of Tcl code with Babel.
+This function is called by `org-babel-execute-src-block'."
+ (let* ((session (cdr (assoc :session params)))
+ (result-params (cdr (assoc :result-params params)))
+ (result-type (cdr (assoc :result-type params)))
+ (full-body (org-babel-expand-body:generic
+ body params (org-babel-variable-assignments:tcl params)))
+ (session (org-babel-tcl-initiate-session session)))
+ (org-babel-reassemble-table
+ (org-babel-tcl-evaluate session full-body result-type)
+ (org-babel-pick-name
+ (cdr (assoc :colname-names params)) (cdr (assoc :colnames params)))
+ (org-babel-pick-name
+ (cdr (assoc :rowname-names params)) (cdr (assoc :rownames params))))))
+
+(defun org-babel-prep-session:tcl (session params)
+ "Prepare SESSION according to the header arguments in PARAMS."
+ (error "Sessions are not supported for Tcl."))
+
+(defun org-babel-variable-assignments:tcl (params)
+ "Return list of tcl statements assigning the block's variables."
+ (mapcar
+ (lambda (pair)
+ (format "set %s %s"
+ (car pair)
+ (org-babel-tcl-var-to-tcl (cdr pair))))
+ (mapcar #'cdr (org-babel-get-header params :var))))
+
+;; helper functions
+
+(defun org-babel-tcl-var-to-tcl (var)
+ "Convert an elisp value to a tcl variable.
+The elisp value, VAR, is converted to a string of tcl source code
+specifying a var of the same value."
+ (if (listp var)
+ (concat "{" (mapconcat #'org-babel-tcl-var-to-tcl var " ") "}")
+ (format "%s" var)))
+
+(defvar org-babel-tcl-buffers '(:default . nil))
+
+(defun org-babel-tcl-initiate-session (&optional session params)
+ "Return nil because sessions are not supported by tcl."
+nil)
+
+(defvar org-babel-tcl-wrapper-method
+ "
+proc main {} {
+ %s
+}
+
+set r [eval main]
+set o [open \"%s\" \"w\"];
+puts $o $r
+flush $o
+close $o
+
+")
+
+(defvar org-babel-tcl-pp-wrapper-method
+ nil)
+
+(defun org-babel-tcl-evaluate (session body &optional result-type)
+ "Pass BODY to the Tcl process in SESSION.
+If RESULT-TYPE equals 'output then return a list of the outputs
+of the statements in BODY, if RESULT-TYPE equals 'value then
+return the value of the last statement in BODY, as elisp."
+ (when session (error "Sessions are not supported for Tcl."))
+ (case result-type
+ (output (org-babel-eval org-babel-tcl-command body))
+ (value (let ((tmp-file (org-babel-temp-file "tcl-")))
+ (org-babel-eval
+ org-babel-tcl-command
+ (format org-babel-tcl-wrapper-method body
+ (org-babel-process-file-name tmp-file 'noquote)))
+ (org-babel-eval-read-file tmp-file)))))
+
+(provide 'ob-tcl)
+
+
+
+;;; ob-tcl.el ends here
diff --git a/contrib/lisp/org-annotate-file.el b/contrib/lisp/org-annotate-file.el
index 55e5a32..bdb9acb 100644
--- a/contrib/lisp/org-annotate-file.el
+++ b/contrib/lisp/org-annotate-file.el
@@ -1,6 +1,6 @@
;;; org-annotate-file.el --- Annotate a file with org syntax
-;; Copyright (C) 2008-2012 Philip Jackson
+;; Copyright (C) 2008-2013 Philip Jackson
;; Author: Philip Jackson <phil@shellarchive.co.uk>
;; Version: 0.2
diff --git a/contrib/lisp/org-bibtex-extras.el b/contrib/lisp/org-bibtex-extras.el
index 8424e62..93c97a9 100644
--- a/contrib/lisp/org-bibtex-extras.el
+++ b/contrib/lisp/org-bibtex-extras.el
@@ -1,6 +1,6 @@
;;; org-bibtex-extras --- extras for working with org-bibtex entries
-;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
;; Author: Eric Schulte <eric dot schulte at gmx dot com>
;; Keywords: outlines, hypermedia, bibtex, d3
@@ -9,12 +9,12 @@
;; This file is not yet part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
@@ -78,7 +78,7 @@ For example, to point to your `obe-bibtex-file' use the following.
(find-file obe-bibtex-file)
(goto-char (point-min))
(while (re-search-forward " :CUSTOM_ID: \\(.+\\)$" nil t)
- (push (org-babel-clean-text-properties (match-string 1))
+ (push (org-no-properties (match-string 1))
obe-citations))
obe-citations)))
@@ -111,7 +111,7 @@ For example, to point to your `obe-bibtex-file' use the following.
(when (obe-goto-citation citation)
(let ((pt (point)))
`((:authors . ,(split-string (org-entry-get pt "AUTHOR") " and " t))
- (:title . ,(org-babel-clean-text-properties (org-get-heading 1 1)))
+ (:title . ,(org-no-properties (org-get-heading 1 1)))
(:journal . ,(org-entry-get pt "JOURNAL")))))))
(defun obe-meta-to-json (meta &optional fields)
diff --git a/contrib/lisp/org-bookmark.el b/contrib/lisp/org-bookmark.el
index 56129d2..44588b6 100644
--- a/contrib/lisp/org-bookmark.el
+++ b/contrib/lisp/org-bookmark.el
@@ -1,5 +1,5 @@
;;; org-bookmark.el - Support for links to bookmark
-;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
;;
;; Author: Tokuya Kameshima <kames AT fa2.so-net.ne.jp>
;; Version: 1.0
@@ -12,7 +12,7 @@
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
@@ -80,7 +80,7 @@ Otherwise prompt the user for the right bookmark to use."
(car bmks)
(completing-read "Bookmark: " bmks nil t nil nil (car bmks))))))
(if bookmark
- (org-store-link-props :link (contact "bookmark:" bookmark)
+ (org-store-link-props :link (concat "bookmark:" bookmark)
:description bookmark))))
(provide 'org-bookmark)
diff --git a/contrib/lisp/org-bullets.el b/contrib/lisp/org-bullets.el
new file mode 100644
index 0000000..2951bf8
--- /dev/null
+++ b/contrib/lisp/org-bullets.el
@@ -0,0 +1,122 @@
+;;; org-bullets.el --- Show bullets in org-mode as UTF-8 characters
+;; Version: 0.2.2
+;; Author: sabof
+;; URL: https://github.com/sabof/org-bullets
+
+;; This file is NOT part of GNU Emacs.
+;;
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 3, 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 ; see the file COPYING. If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; The project is hosted at https://github.com/sabof/org-bullets
+;; The latest version, and all the relevant information can be found there.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(defgroup org-bullets nil
+ "Display bullets as UTF-8 characters."
+ :group 'org-appearance)
+
+;; A nice collection of unicode bullets:
+;; http://nadeausoftware.com/articles/2007/11/latency_friendly_customized_bullets_using_unicode_characters
+(defcustom org-bullets-bullet-list
+ '(;;; Large
+ "◉"
+ "○"
+ "✸"
+ "✿"
+ ;; ♥ ● ◇ ✚ ✜ ☯ ◆ ♠ ♣ ♦ ☢ ❀ ◆ ◖ ▶
+ ;;; Small
+ ;; ► • ★ ▸
+ )
+ "This variable contains the list of bullets.
+It can contain any number of one-character strings.
+For levels beyond the size of the list, the stars will be
+displayed using the first items again."
+ :group 'org-bullets
+ :type '(repeat (string :tag "Bullet character")))
+
+(defcustom org-bullets-face-name nil
+ "Allows to override `org-mode' bullets face.
+If set to a name of a face, that face will be used.
+Otherwise the face of the heading level will be used."
+ :group 'org-bullets
+ :type 'symbol)
+
+(defvar org-bullets-bullet-map
+ '(keymap
+ (mouse-1 . org-cycle)
+ (mouse-2 . (lambda (e)
+ (interactive "e")
+ (mouse-set-point e)
+ (org-cycle))))
+ "Mouse events for bullets.
+If this is undesirable, one can remove them with
+
+\(setcdr org-bullets-bullet-map nil\)")
+
+(defun org-bullets-level-char (level)
+ "Return a character corresponding to LEVEL."
+ (string-to-char
+ (nth (mod (1- level)
+ (length org-bullets-bullet-list))
+ org-bullets-bullet-list)))
+
+;;;###autoload
+(define-minor-mode org-bullets-mode
+ "UTF-8 bullets for `org-mode'."
+ nil nil nil
+ (let* ((keyword
+ `((,org-outline-regexp-bol
+ (0 (let (( level (- (match-end 0) (match-beginning 0) 1)))
+ (compose-region (- (match-end 0) 2)
+ (- (match-end 0) 1)
+ (org-bullets-level-char level))
+ (when (facep org-bullets-face-name)
+ (put-text-property (- (match-end 0) 2)
+ (- (match-end 0) 1)
+ 'face
+ org-bullets-face-name))
+ (put-text-property (match-beginning 0)
+ (- (match-end 0) 2)
+ 'face (list :foreground
+ (face-attribute
+ 'default :background)))
+ (put-text-property (match-beginning 0)
+ (match-end 0)
+ 'keymap
+ org-bullets-bullet-map)
+ nil))))))
+ (if org-bullets-mode
+ (progn (font-lock-add-keywords nil keyword)
+ (font-lock-fontify-buffer))
+ (save-excursion
+ (goto-char (point-min))
+ (font-lock-remove-keywords nil keyword)
+ (while (re-search-forward org-outline-regexp-bol nil t)
+ (decompose-region (match-beginning 0) (match-end 0)))
+ (font-lock-fontify-buffer)))))
+
+(provide 'org-bullets)
+
+;; Local Variables:
+;; coding: utf-8-emacs
+;; End:
+
+;;; org-bullets.el ends here
diff --git a/contrib/lisp/org-checklist.el b/contrib/lisp/org-checklist.el
index 1345a55..faa5998 100644
--- a/contrib/lisp/org-checklist.el
+++ b/contrib/lisp/org-checklist.el
@@ -1,11 +1,13 @@
;;; org-checklist.el --- org functions for checklist handling
-;; Copyright (C) 2008-2012 James TD Smith
+;; Copyright (C) 2008-2013 James TD Smith
;; Author: James TD Smith (@ ahktenzero (. mohorovi cc))
;; Version: 1.0
;; Keywords: org, checklists
;;
+;; This file is not part of GNU Emacs.
+;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
@@ -17,8 +19,7 @@
;; 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, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/contrib/lisp/org-choose.el b/contrib/lisp/org-choose.el
index 3513fe9..8e5935d 100644
--- a/contrib/lisp/org-choose.el
+++ b/contrib/lisp/org-choose.el
@@ -1,8 +1,6 @@
-;;;_ org-choose.el --- decision management for org-mode
+;;; org-choose.el --- decision management for org-mode
-;;;_. Headers
-;;;_ , License
-;; Copyright (C) 2009-2012 Tom Breton (Tehom)
+;; Copyright (C) 2009-2013 Tom Breton (Tehom)
;; This file is not part of GNU Emacs.
@@ -24,13 +22,13 @@
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
-;;;_ , Commentary:
+;;; Commentary:
-; This is code to support decision management. It lets you treat a
-; group of sibling items in org-mode as alternatives in a decision.
+;; This is code to support decision management. It lets you treat a
+;; group of sibling items in org-mode as alternatives in a decision.
-; There are no user commands in this file. You use it by:
-; * Loading it (manually or by M-x customize-apropos org-modules)
+;; There are no user commands in this file. You use it by:
+;; * Loading it (manually or by M-x customize-apropos org-modules)
;; * Setting up at least one set of TODO keywords with the
;; interpretation "choose" by either:
@@ -61,31 +59,30 @@
;; * All the other TODO commands are available and behave essentially
;; the normal way.
-
-;;;_ , Requires
+;;; Requires
(require 'org)
-;(eval-when-compile
-; (require 'cl))
+ ;(eval-when-compile
+ ; (require 'cl))
(require 'cl)
-;;;_. Body
-;;;_ , The variables
+;;; Body
+;;; The variables
(defstruct (org-choose-mark-data. (:type list))
- "The format of an entry in org-choose-mark-data.
+ "The format of an entry in org-choose-mark-data.
Indexes are 0-based or `nil'.
"
- keyword
- bot-lower-range
- top-upper-range
- range-length
- static-default
- all-keywords)
+ keyword
+ bot-lower-range
+ top-upper-range
+ range-length
+ static-default
+ all-keywords)
(defvar org-choose-mark-data
- ()
- "Alist of information for choose marks.
+ ()
+ "Alist of information for choose marks.
Each entry is an `org-choose-mark-data.'" )
(make-variable-buffer-local 'org-choose-mark-data)
@@ -93,426 +90,394 @@ Each entry is an `org-choose-mark-data.'" )
;;;_ . org-choose-filter-one
(defun org-choose-filter-one (i)
- "Return a list of
+ "Return a list of
* a canonized version of the string
* optionally one symbol"
- (if
+ (if
(not
- (string-match "(.*)" i))
+ (string-match "(.*)" i))
(list i i)
- (let*
- (
- (end-text (match-beginning 0))
- (vanilla-text (substring i 0 end-text))
- ;;Get the parenthesized part.
- (match (match-string 0 i))
- ;;Remove the parentheses.
- (args (substring match 1 -1))
- ;;Split it
- (arglist
- (let
- ((arglist-x (org-split-string args ",")))
- ;;When string starts with "," `split-string' doesn't
- ;;make a first arg, so in that case make one
- ;;manually.
- (if
- (string-match "^," args)
- (cons nil arglist-x)
- arglist-x)))
- (decision-arg (second arglist))
- (type
- (cond
- ((string= decision-arg "0")
- 'default-mark)
- ((string= decision-arg "+")
- 'top-upper-range)
- ((string= decision-arg "-")
- 'bot-lower-range)
- (t nil)))
- (vanilla-arg (first arglist))
- (vanilla-mark
- (if vanilla-arg
- (concat vanilla-text "("vanilla-arg")")
- vanilla-text)))
- (if type
- (list vanilla-text vanilla-mark type)
- (list vanilla-text vanilla-mark)))))
+ (let*
+ (
+ (end-text (match-beginning 0))
+ (vanilla-text (substring i 0 end-text))
+ ;;Get the parenthesized part.
+ (match (match-string 0 i))
+ ;;Remove the parentheses.
+ (args (substring match 1 -1))
+ ;;Split it
+ (arglist
+ (let
+ ((arglist-x (org-split-string args ",")))
+ ;;When string starts with "," `split-string' doesn't
+ ;;make a first arg, so in that case make one
+ ;;manually.
+ (if
+ (string-match "^," args)
+ (cons nil arglist-x)
+ arglist-x)))
+ (decision-arg (second arglist))
+ (type
+ (cond
+ ((string= decision-arg "0")
+ 'default-mark)
+ ((string= decision-arg "+")
+ 'top-upper-range)
+ ((string= decision-arg "-")
+ 'bot-lower-range)
+ (t nil)))
+ (vanilla-arg (first arglist))
+ (vanilla-mark
+ (if vanilla-arg
+ (concat vanilla-text "("vanilla-arg")")
+ vanilla-text)))
+ (if type
+ (list vanilla-text vanilla-mark type)
+ (list vanilla-text vanilla-mark)))))
;;;_ . org-choose-setup-vars
(defun org-choose-setup-vars (bot-lower-range top-upper-range
- static-default num-items all-mark-texts)
- "Add to org-choose-mark-data according to arguments"
-
- (let*
- (
- (tail
- ;;If there's no bot-lower-range or no default, we don't
- ;;have ranges.
- (cdr
- (if (and static-default bot-lower-range)
- (let*
- (
- ;;If there's no top-upper-range, use the last
- ;;item.
- (top-upper-range
- (or top-upper-range (1- num-items)))
- (lower-range-length
- (1+ (- static-default bot-lower-range)))
- (upper-range-length
- (- top-upper-range static-default))
- (range-length
- (min upper-range-length lower-range-length)))
-
-
- (make-org-choose-mark-data.
- :keyword nil
- :bot-lower-range bot-lower-range
- :top-upper-range top-upper-range
- :range-length range-length
- :static-default static-default
- :all-keywords all-mark-texts))
-
- (make-org-choose-mark-data.
- :keyword nil
- :bot-lower-range nil
- :top-upper-range nil
- :range-length nil
- :static-default (or static-default 0)
- :all-keywords all-mark-texts)))))
-
- (dolist (text all-mark-texts)
- (pushnew (cons text tail)
- org-choose-mark-data
- :test
- #'(lambda (a b)
- (equal (car a) (car b)))))))
-
-
-
-
-;;;_ . org-choose-filter-tail
+ static-default num-items all-mark-texts)
+ "Add to org-choose-mark-data according to arguments"
+ (let*
+ ((tail
+ ;;If there's no bot-lower-range or no default, we don't
+ ;;have ranges.
+ (cdr
+ (if (and static-default bot-lower-range)
+ (let*
+ ;;If there's no top-upper-range, use the last
+ ;;item.
+ ((top-upper-range
+ (or top-upper-range (1- num-items)))
+ (lower-range-length
+ (1+ (- static-default bot-lower-range)))
+ (upper-range-length
+ (- top-upper-range static-default))
+ (range-length
+ (min upper-range-length lower-range-length)))
+ (make-org-choose-mark-data.
+ :keyword nil
+ :bot-lower-range bot-lower-range
+ :top-upper-range top-upper-range
+ :range-length range-length
+ :static-default static-default
+ :all-keywords all-mark-texts))
+ (make-org-choose-mark-data.
+ :keyword nil
+ :bot-lower-range nil
+ :top-upper-range nil
+ :range-length nil
+ :static-default (or static-default 0)
+ :all-keywords all-mark-texts)))))
+ (dolist (text all-mark-texts)
+ (pushnew (cons text tail)
+ org-choose-mark-data
+ :test
+ #'(lambda (a b)
+ (equal (car a) (car b)))))))
+
+;;; org-choose-filter-tail
(defun org-choose-filter-tail (raw)
- "Return a translation of RAW to vanilla and set appropriate
+ "Return a translation of RAW to vanilla and set appropriate
buffer-local variables.
RAW is a list of strings representing the input text of a choose
interpretation."
- (let
+ (let
((vanilla-list nil)
- (all-mark-texts nil)
- (index 0)
- bot-lower-range top-upper-range range-length static-default)
- (dolist (i raw)
- (destructuring-bind
- (vanilla-text vanilla-mark &optional type)
- (org-choose-filter-one i)
- (cond
- ((eq type 'bot-lower-range)
- (setq bot-lower-range index))
- ((eq type 'top-upper-range)
- (setq top-upper-range index))
- ((eq type 'default-mark)
- (setq static-default index)))
- (incf index)
- (push vanilla-text all-mark-texts)
- (push vanilla-mark vanilla-list)))
-
- (org-choose-setup-vars bot-lower-range top-upper-range
- static-default index (reverse all-mark-texts))
- (nreverse vanilla-list)))
-
-;;;_ . org-choose-setup-filter
+ (all-mark-texts nil)
+ (index 0)
+ bot-lower-range top-upper-range range-length static-default)
+ (dolist (i raw)
+ (destructuring-bind
+ (vanilla-text vanilla-mark &optional type)
+ (org-choose-filter-one i)
+ (cond
+ ((eq type 'bot-lower-range)
+ (setq bot-lower-range index))
+ ((eq type 'top-upper-range)
+ (setq top-upper-range index))
+ ((eq type 'default-mark)
+ (setq static-default index)))
+ (incf index)
+ (push vanilla-text all-mark-texts)
+ (push vanilla-mark vanilla-list)))
+
+ (org-choose-setup-vars bot-lower-range top-upper-range
+ static-default index (reverse all-mark-texts))
+ (nreverse vanilla-list)))
+
+;;; org-choose-setup-filter
(defun org-choose-setup-filter (raw)
- "A setup filter for choose interpretations."
- (when (eq (car raw) 'choose)
- (cons
- 'choose
- (org-choose-filter-tail (cdr raw)))))
+ "A setup filter for choose interpretations."
+ (when (eq (car raw) 'choose)
+ (cons
+ 'choose
+ (org-choose-filter-tail (cdr raw)))))
-;;;_ . org-choose-conform-after-promotion
+;;; org-choose-conform-after-promotion
(defun org-choose-conform-after-promotion (entry-pos keywords highest-ok-ix)
"Conform the current item after another item was promoted"
-
- (unless
+ (unless
;;Skip the entry that triggered this by skipping any entry with
;;the same starting position. plist uses the start of the
;;header line as the position, but map no longer does, so we
;;have to go back to the heading.
(=
- (save-excursion
- (org-back-to-heading)
- (point))
- entry-pos)
- (let
- ((ix
- (org-choose-get-entry-index keywords)))
- ;;If the index of the entry exceeds the highest allowable
- ;;index, change it to that.
- (when (and ix
- (> ix highest-ok-ix))
- (org-todo
- (nth highest-ok-ix keywords))))))
+ (save-excursion
+ (org-back-to-heading)
+ (point))
+ entry-pos)
+ (let
+ ((ix
+ (org-choose-get-entry-index keywords)))
+ ;;If the index of the entry exceeds the highest allowable
+ ;;index, change it to that.
+ (when (and ix
+ (> ix highest-ok-ix))
+ (org-todo
+ (nth highest-ok-ix keywords))))))
;;;_ . org-choose-conform-after-demotion
(defun org-choose-conform-after-demotion (entry-pos keywords
- raise-to-ix
- old-highest-ok-ix)
+ raise-to-ix
+ old-highest-ok-ix)
"Conform the current item after another item was demoted."
-
- (unless
+ (unless
;;Skip the entry that triggered this.
(=
- (save-excursion
- (org-back-to-heading)
- (point))
- entry-pos)
- (let
- ((ix
- (org-choose-get-entry-index keywords)))
- ;;If the index of the entry was at or above the old allowable
- ;;position, change it to the new mirror position if there is
- ;;one.
- (when (and
- ix
- raise-to-ix
- (>= ix old-highest-ok-ix))
- (org-todo
- (nth raise-to-ix keywords))))))
-
-;;;_ , org-choose-keep-sensible (the org-trigger-hook function)
+ (save-excursion
+ (org-back-to-heading)
+ (point))
+ entry-pos)
+ (let
+ ((ix
+ (org-choose-get-entry-index keywords)))
+ ;;If the index of the entry was at or above the old allowable
+ ;;position, change it to the new mirror position if there is
+ ;;one.
+ (when (and
+ ix
+ raise-to-ix
+ (>= ix old-highest-ok-ix))
+ (org-todo
+ (nth raise-to-ix keywords))))))
+
+;;; org-choose-keep-sensible (the org-trigger-hook function)
(defun org-choose-keep-sensible (change-plist)
"Bring the other items back into a sensible state after an item's
setting was changed."
- (let*
+ (let*
( (from (plist-get change-plist :from))
(to (plist-get change-plist :to))
(entry-pos
- (set-marker
- (make-marker)
- (plist-get change-plist :position)))
+ (set-marker
+ (make-marker)
+ (plist-get change-plist :position)))
(kwd-data
- (assoc to org-todo-kwd-alist)))
- (when
- (eq (nth 1 kwd-data) 'choose)
- (let*
- (
- (data
- (assoc to org-choose-mark-data))
- (keywords
- (org-choose-mark-data.-all-keywords data))
- (old-index
- (org-choose-get-index-in-keywords
- from
- keywords))
- (new-index
- (org-choose-get-index-in-keywords
- to
- keywords))
- (highest-ok-ix
- (org-choose-highest-other-ok
- new-index
- data))
- (funcdata
- (cond
- ;;The entry doesn't participate in conformance,
- ;;so give `nil' which does nothing.
- ((not highest-ok-ix) nil)
- ;;The entry was created or promoted
- ((or
- (not old-index)
- (> new-index old-index))
- (list
- #'org-choose-conform-after-promotion
- entry-pos keywords
- highest-ok-ix))
- (t ;;Otherwise the entry was demoted.
- (let
- (
- (raise-to-ix
- (min
- highest-ok-ix
- (org-choose-mark-data.-static-default
- data)))
- (old-highest-ok-ix
- (org-choose-highest-other-ok
- old-index
- data)))
-
- (list
- #'org-choose-conform-after-demotion
- entry-pos
- keywords
- raise-to-ix
- old-highest-ok-ix))))))
-
- (if funcdata
- ;;The funny-looking names are to make variable capture
- ;;unlikely. (Poor-man's lexical bindings).
- (destructuring-bind (func-d473 . args-46k) funcdata
- (let
- ((map-over-entries
- (org-choose-get-fn-map-group))
- ;;We may call `org-todo', so let various hooks
- ;;`nil' so we don't cause loops.
- org-after-todo-state-change-hook
- org-trigger-hook
- org-blocker-hook
- org-todo-get-default-hook
- ;;Also let this alist `nil' so we don't log
- ;;secondary transitions.
- org-todo-log-states)
- ;;Map over group
- (funcall map-over-entries
- #'(lambda ()
+ (assoc to org-todo-kwd-alist)))
+ (when
+ (eq (nth 1 kwd-data) 'choose)
+ (let*
+ (
+ (data
+ (assoc to org-choose-mark-data))
+ (keywords
+ (org-choose-mark-data.-all-keywords data))
+ (old-index
+ (org-choose-get-index-in-keywords
+ from
+ keywords))
+ (new-index
+ (org-choose-get-index-in-keywords
+ to
+ keywords))
+ (highest-ok-ix
+ (org-choose-highest-other-ok
+ new-index
+ data))
+ (funcdata
+ (cond
+ ;;The entry doesn't participate in conformance,
+ ;;so give `nil' which does nothing.
+ ((not highest-ok-ix) nil)
+ ;;The entry was created or promoted
+ ((or
+ (not old-index)
+ (> new-index old-index))
+ (list
+ #'org-choose-conform-after-promotion
+ entry-pos keywords
+ highest-ok-ix))
+ (t ;;Otherwise the entry was demoted.
+ (let
+ (
+ (raise-to-ix
+ (min
+ highest-ok-ix
+ (org-choose-mark-data.-static-default
+ data)))
+ (old-highest-ok-ix
+ (org-choose-highest-other-ok
+ old-index
+ data)))
+ (list
+ #'org-choose-conform-after-demotion
+ entry-pos
+ keywords
+ raise-to-ix
+ old-highest-ok-ix))))))
+ (if funcdata
+ ;;The funny-looking names are to make variable capture
+ ;;unlikely. (Poor-man's lexical bindings).
+ (destructuring-bind (func-d473 . args-46k) funcdata
+ (let
+ ((map-over-entries
+ (org-choose-get-fn-map-group))
+ ;;We may call `org-todo', so let various hooks
+ ;;`nil' so we don't cause loops.
+ org-after-todo-state-change-hook
+ org-trigger-hook
+ org-blocker-hook
+ org-todo-get-default-hook
+ ;;Also let this alist `nil' so we don't log
+ ;;secondary transitions.
+ org-todo-log-states)
+ ;;Map over group
+ (funcall map-over-entries
+ #'(lambda ()
(apply func-d473 args-46k))))))))
+ ;;Remove the marker
+ (set-marker entry-pos nil)))
- ;;Remove the marker
- (set-marker entry-pos nil)))
-
-
-
-;;;_ , Getting the default mark
-;;;_ . org-choose-get-index-in-keywords
+;;; Getting the default mark
+;;; org-choose-get-index-in-keywords
(defun org-choose-get-index-in-keywords (ix all-keywords)
"Return the index of the current entry."
-
- (if ix
+ (if ix
(position ix all-keywords
- :test #'equal)))
+ :test #'equal)))
-;;;_ . org-choose-get-entry-index
+;;; org-choose-get-entry-index
(defun org-choose-get-entry-index (all-keywords)
- "Return index of current entry."
-
- (let*
+ "Return index of current entry."
+ (let*
((state (org-entry-get (point) "TODO")))
- (org-choose-get-index-in-keywords state all-keywords)))
+ (org-choose-get-index-in-keywords state all-keywords)))
-;;;_ . org-choose-get-fn-map-group
+;;; org-choose-get-fn-map-group
(defun org-choose-get-fn-map-group ()
- "Return a function to map over the group"
-
- #'(lambda (fn)
- (require 'org-agenda) ;; `org-map-entries' seems to need it.
- (save-excursion
- (unless (org-up-heading-safe)
- (error "Choosing is only supported between siblings in a tree, not on top level"))
- (let
- ((level (org-reduced-level (org-outline-level))))
- (save-restriction
- (org-map-entries
- fn
- (format "LEVEL=%d" level)
- 'tree))))))
-
-;;;_ . org-choose-get-highest-mark-index
+ "Return a function to map over the group"
+ #'(lambda (fn)
+ (require 'org-agenda) ;; `org-map-entries' seems to need it.
+ (save-excursion
+ (unless (org-up-heading-safe)
+ (error "Choosing is only supported between siblings in a tree, not on top level"))
+ (let
+ ((level (org-reduced-level (org-outline-level))))
+ (save-restriction
+ (org-map-entries
+ fn
+ (format "LEVEL=%d" level)
+ 'tree))))))
+
+;;; org-choose-get-highest-mark-index
(defun org-choose-get-highest-mark-index (keywords)
- "Get the index of the highest current mark in the group.
+ "Get the index of the highest current mark in the group.
If there is none, return 0"
-
- (let*
- (
- ;;Func maps over applicable entries.
- (map-over-entries
- (org-choose-get-fn-map-group))
-
- (indexes-list
- (remove nil
- (funcall map-over-entries
- #'(lambda ()
- (org-choose-get-entry-index keywords))))))
- (if
- indexes-list
- (apply #'max indexes-list)
- 0)))
-
-
-;;;_ . org-choose-highest-ok
+ (let*
+ ;;Func maps over applicable entries.
+ ((map-over-entries
+ (org-choose-get-fn-map-group))
+ (indexes-list
+ (remove nil
+ (funcall map-over-entries
+ #'(lambda ()
+ (org-choose-get-entry-index keywords))))))
+ (if
+ indexes-list
+ (apply #'max indexes-list)
+ 0)))
+
+;;; org-choose-highest-ok
(defun org-choose-highest-other-ok (ix data)
"Return the highest index that any choose mark can sensibly have,
given that another mark has index IX.
DATA must be a `org-choose-mark-data.'."
+ (let
+ ((bot-lower-range
+ (org-choose-mark-data.-bot-lower-range data))
+ (top-upper-range
+ (org-choose-mark-data.-top-upper-range data))
+ (range-length
+ (org-choose-mark-data.-range-length data)))
+ (when (and ix bot-lower-range)
+ (let*
+ ((delta
+ (- top-upper-range ix)))
+ (unless
+ (< range-length delta)
+ (+ bot-lower-range delta))))))
- (let
- (
- (bot-lower-range
- (org-choose-mark-data.-bot-lower-range data))
- (top-upper-range
- (org-choose-mark-data.-top-upper-range data))
- (range-length
- (org-choose-mark-data.-range-length data)))
- (when (and ix bot-lower-range)
- (let*
- ((delta
- (- top-upper-range ix)))
- (unless
- (< range-length delta)
- (+ bot-lower-range delta))))))
-
-;;;_ . org-choose-get-default-mark-index
+;;; org-choose-get-default-mark-index
(defun org-choose-get-default-mark-index (data)
"Return the index of the default mark in a choose interpretation.
DATA must be a `org-choose-mark-data.'."
-
-
- (or
- (let
- ((highest-mark-index
- (org-choose-get-highest-mark-index
- (org-choose-mark-data.-all-keywords data))))
- (org-choose-highest-other-ok
- highest-mark-index data))
- (org-choose-mark-data.-static-default data)))
-
-
-
-;;;_ . org-choose-get-mark-N
+ (or
+ (let
+ ((highest-mark-index
+ (org-choose-get-highest-mark-index
+ (org-choose-mark-data.-all-keywords data))))
+ (org-choose-highest-other-ok
+ highest-mark-index data))
+ (org-choose-mark-data.-static-default data)))
+
+;;; org-choose-get-mark-N
(defun org-choose-get-mark-N (n data)
- "Get the text of the nth mark in a choose interpretation."
+ "Get the text of the nth mark in a choose interpretation."
- (let*
+ (let*
((l (org-choose-mark-data.-all-keywords data)))
- (nth n l)))
+ (nth n l)))
-;;;_ . org-choose-get-default-mark
+;;; org-choose-get-default-mark
(defun org-choose-get-default-mark (new-mark old-mark)
- "Get the default mark IFF in a choose interpretation.
+ "Get the default mark IFF in a choose interpretation.
NEW-MARK and OLD-MARK are the text of the new and old marks."
-
- (let*
- (
- (old-kwd-data
- (assoc old-mark org-todo-kwd-alist))
- (new-kwd-data
- (assoc new-mark org-todo-kwd-alist))
- (becomes-choose
- (and
- (or
- (not old-kwd-data)
- (not
- (eq (nth 1 old-kwd-data) 'choose)))
- (eq (nth 1 new-kwd-data) 'choose))))
- (when
- becomes-choose
- (let
- ((new-mark-data
- (assoc new-mark org-choose-mark-data)))
- (if
- new-mark
- (org-choose-get-mark-N
- (org-choose-get-default-mark-index
- new-mark-data)
- new-mark-data)
- (error "Somehow got an unrecognizable mark"))))))
-
-;;;_ , Setting it all up
+ (let*
+ ((old-kwd-data
+ (assoc old-mark org-todo-kwd-alist))
+ (new-kwd-data
+ (assoc new-mark org-todo-kwd-alist))
+ (becomes-choose
+ (and
+ (or
+ (not old-kwd-data)
+ (not
+ (eq (nth 1 old-kwd-data) 'choose)))
+ (eq (nth 1 new-kwd-data) 'choose))))
+ (when
+ becomes-choose
+ (let
+ ((new-mark-data
+ (assoc new-mark org-choose-mark-data)))
+ (if
+ new-mark
+ (org-choose-get-mark-N
+ (org-choose-get-default-mark-index
+ new-mark-data)
+ new-mark-data)
+ (error "Somehow got an unrecognizable mark"))))))
+
+;;; Setting it all up
(eval-after-load "org"
'(progn
@@ -524,19 +489,8 @@ NEW-MARK and OLD-MARK are the text of the new and old marks."
#'org-choose-keep-sensible)
(add-to-list 'org-todo-interpretation-widgets
'(:tag "Choose (to record decisions)" choose)
- 'append)
- ))
-
-
-;;;_. Footers
-;;;_ , Provides
+ 'append)))
(provide 'org-choose)
-;;;_ * Local emacs vars.
-;;;_ + Local variables:
-;;;_ + End:
-
-;;;_ , End
-
;;; org-choose.el ends here
diff --git a/contrib/lisp/org-collector.el b/contrib/lisp/org-collector.el
index 089e8ad..60b9069 100644
--- a/contrib/lisp/org-collector.el
+++ b/contrib/lisp/org-collector.el
@@ -1,6 +1,6 @@
;;; org-collector --- collect properties into tables
-;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
;; Author: Eric Schulte <schulte dot eric at gmail dot com>
;; Keywords: outlines, hypermedia, calendar, wp, experimentation,
@@ -10,12 +10,12 @@
;; This file is not yet part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
diff --git a/contrib/lisp/org-colview-xemacs.el b/contrib/lisp/org-colview-xemacs.el
new file mode 100644
index 0000000..63c0238
--- /dev/null
+++ b/contrib/lisp/org-colview-xemacs.el
@@ -0,0 +1,1721 @@
+;;; org-colview-xemacs.el --- Column View in Org-mode, XEmacs-specific version
+
+;; Copyright (C) 2004-2013
+;; Carsten Dominik
+
+;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Keywords: outlines, hypermedia, calendar, wp
+;; Homepage: http://orgmode.org
+;;
+;; This file is part of Org mode, it is not part of GNU Emacs.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+
+;; This file contains the column view for Org.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'org)
+
+(declare-function org-agenda-redo "org-agenda" ())
+
+
+;;; Define additional faces for column view
+
+(when (featurep 'xemacs)
+
+ (defface org-columns-level-1;; font-lock-function-name-face
+ (org-compatible-face
+ 'outline-1
+ '((((class color) (min-colors 88) (background light)) (:foreground "Blue1" :background "grey90"))
+ (((class color) (min-colors 88) (background dark)) (:foreground "LightSkyBlue" :background "grey30"))
+ (((class color) (min-colors 16) (background light)) (:foreground "Blue" :background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "LightSkyBlue" :background "grey30"))
+ (((class color) (min-colors 8)) (:foreground "blue" :bold t))
+ (t (:bold t))))
+ "Face used for columns-level 1 headlines."
+ :group 'org-faces)
+
+ (defface org-columns-level-2;; font-lock-variable-name-face
+ (org-compatible-face
+ 'outline-2
+ '((((class color) (min-colors 16) (background light)) (:foreground "DarkGoldenrod" :background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "LightGoldenrod" :background "grey30"))
+ (((class color) (min-colors 8) (background light)) (:foreground "yellow" :background "grey90"))
+ (((class color) (min-colors 8) (background dark)) (:foreground "yellow" :bold t))
+ (t (:bold t))))
+ "Face used for columns-level 2 headlines."
+ :group 'org-faces)
+
+ (defface org-columns-level-3;; font-lock-keyword-face
+ (org-compatible-face
+ 'outline-3
+ '((((class color) (min-colors 88) (background light)) (:foreground "Purple" :background "grey90"))
+ (((class color) (min-colors 88) (background dark)) (:foreground "Cyan1" :background "grey30"))
+ (((class color) (min-colors 16) (background light)) (:foreground "Purple" :background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "Cyan" :background "grey30"))
+ (((class color) (min-colors 8) (background light)) (:foreground "purple" :bold t))
+ (((class color) (min-colors 8) (background dark)) (:foreground "cyan" :bold t))
+ (t (:bold t))))
+ "Face used for columns-level 3 headlines."
+ :group 'org-faces)
+
+ (defface org-columns-level-4;; font-lock-comment-face
+ (org-compatible-face
+ 'outline-4
+ '((((class color) (min-colors 88) (background light)) (:foreground "Firebrick" :background "grey90"))
+ (((class color) (min-colors 88) (background dark)) (:foreground "chocolate1" :background "grey30"))
+ (((class color) (min-colors 16) (background light)) (:foreground "red"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "red1"))
+ (((class color) (min-colors 8) (background light)) (:foreground "red" :bold t))
+ (((class color) (min-colors 8) (background dark)) (:foreground "red" :bold t))
+ (t (:bold t))))
+ "Face used for columns-level 4 headlines."
+ :group 'org-faces)
+
+ (defface org-columns-level-5;; font-lock-type-face
+ (org-compatible-face
+ 'outline-5
+ '((((class color) (min-colors 16) (background light)) (:foreground "ForestGreen" :background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "PaleGreen" :background "grey30"))
+ (((class color) (min-colors 8)) (:foreground "green"))))
+ "Face used for columns-level 5 headlines."
+ :group 'org-faces)
+
+ (defface org-columns-level-6;; font-lock-constant-face
+ (org-compatible-face
+ 'outline-6
+ '((((class color) (min-colors 16) (background light)) (:foreground "CadetBlue" :background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "Aquamarine" :background "grey30"))
+ (((class color) (min-colors 8)) (:foreground "magenta"))))
+ "Face used for columns-level 6 headlines."
+ :group 'org-faces)
+
+ (defface org-columns-level-7;; font-lock-builtin-face
+ (org-compatible-face
+ 'outline-7
+ '((((class color) (min-colors 16) (background light)) (:foreground "Orchid" :background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "LightSteelBlue" :background "grey30"))
+ (((class color) (min-colors 8)) (:foreground "blue"))))
+ "Face used for columns-level 7 headlines."
+ :group 'org-faces)
+
+ (defface org-columns-level-8;; font-lock-string-face
+ (org-compatible-face
+ 'outline-8
+ '((((class color) (min-colors 16) (background light)) (:foreground "RosyBrown" :background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:foreground "LightSalmon" :background "grey30"))
+ (((class color) (min-colors 8)) (:foreground "green"))))
+ "Face used for columns-level 8 headlines."
+ :group 'org-faces)
+
+
+ (defface org-columns-space;; font-lock-function-name-face
+ (org-compatible-face
+ 'outline-1
+ '((((class color) (min-colors 88) (background light)) (:background "grey90"))
+ (((class color) (min-colors 88) (background dark)) (:background "grey30"))
+ (((class color) (min-colors 16) (background light)) (:background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:background "grey30"))
+ (((class color) (min-colors 8)) (:bold t :underline t))))
+ "Face used for columns space headlines."
+ :group 'org-faces)
+
+ (defface org-columns-space1;; font-lock-function-name-face
+ (org-compatible-face
+ 'outline-1
+ '((((class color) (min-colors 88) (background light)) (:background "grey90"))
+ (((class color) (min-colors 88) (background dark)) (:background "grey30"))
+ (((class color) (min-colors 16) (background light)) (:background "grey90"))
+ (((class color) (min-colors 16) (background dark)) (:background "grey30"))
+ (((class color) (min-colors 8)) (:bold t :underline t))))
+ "Face used for columns space headlines."
+ :group 'org-faces)
+ )
+
+(when (featurep 'xemacs)
+ (defconst org-columns-level-faces
+ '(org-columns-level-1
+ org-columns-level-2 org-columns-level-3
+ org-columns-level-4 org-columns-level-5 org-columns-level-6
+ org-columns-level-7 org-columns-level-8
+ ))
+
+ (defun org-get-columns-level-face (n)
+ "Get the right face for match N in font-lock matching of headlines."
+ (setq org-l (- (match-end 2) (match-beginning 1) 1))
+ (if org-odd-levels-only (setq org-l (1+ (/ org-l 2))))
+ (setq org-f (nth (% (1- org-l) org-n-level-faces) org-columns-level-faces))
+ (cond
+ ((eq n 1) (if org-hide-leading-stars 'org-hide org-f))
+ ((eq n 2) org-f)
+ (t (if org-level-color-stars-only nil org-f))))
+ )
+
+
+;;; Column View
+
+(defvar org-columns-overlays nil
+ "Holds the list of current column overlays.")
+
+(defvar org-columns-current-fmt nil
+ "Local variable, holds the currently active column format.")
+(make-variable-buffer-local 'org-columns-current-fmt)
+(defvar org-columns-current-fmt-compiled nil
+ "Local variable, holds the currently active column format.
+This is the compiled version of the format.")
+(make-variable-buffer-local 'org-columns-current-fmt-compiled)
+(defvar org-columns-current-widths nil
+ "Local variable, holds the currently widths of fields.")
+(make-variable-buffer-local 'org-columns-current-widths)
+(defvar org-columns-current-maxwidths nil
+ "Local variable, holds the currently active maximum column widths.")
+(make-variable-buffer-local 'org-columns-current-maxwidths)
+(defvar org-columns-begin-marker (make-marker)
+ "Points to the position where last a column creation command was called.")
+(defvar org-columns-top-level-marker (make-marker)
+ "Points to the position where current columns region starts.")
+
+(defvar org-columns-map (make-sparse-keymap)
+ "The keymap valid in column display.")
+
+(defun org-columns-content ()
+ "Switch to contents view while in columns view."
+ (interactive)
+ (org-overview)
+ (org-content))
+
+(org-defkey org-columns-map "c" 'org-columns-content)
+(org-defkey org-columns-map "o" 'org-overview)
+(org-defkey org-columns-map "e" 'org-columns-edit-value)
+(org-defkey org-columns-map "\C-c\C-t" 'org-columns-todo)
+(org-defkey org-columns-map "\C-c\C-c" 'org-columns-set-tags-or-toggle)
+(org-defkey org-columns-map "\C-c\C-o" 'org-columns-open-link)
+(org-defkey org-columns-map "v" 'org-columns-show-value)
+(org-defkey org-columns-map "q" 'org-columns-quit)
+(org-defkey org-columns-map "r" 'org-columns-redo)
+(org-defkey org-columns-map "g" 'org-columns-redo)
+(org-defkey org-columns-map [left] 'org-columns-backward-char)
+(org-defkey org-columns-map "\M-b" 'org-columns-backward-char)
+(org-defkey org-columns-map "a" 'org-columns-edit-allowed)
+(org-defkey org-columns-map "s" 'org-columns-edit-attributes)
+(org-defkey org-columns-map "\M-f" 'org-columns-forward-char)
+(org-defkey org-columns-map [right] 'org-columns-forward-char)
+(org-defkey org-columns-map [(shift right)] 'org-columns-next-allowed-value)
+(org-defkey org-columns-map "n" 'org-columns-next-allowed-value)
+(org-defkey org-columns-map [(shift left)] 'org-columns-previous-allowed-value)
+(org-defkey org-columns-map "p" 'org-columns-previous-allowed-value)
+(org-defkey org-columns-map "<" 'org-columns-narrow)
+(org-defkey org-columns-map ">" 'org-columns-widen)
+(org-defkey org-columns-map [(meta right)] 'org-columns-move-right)
+(org-defkey org-columns-map [(meta left)] 'org-columns-move-left)
+(org-defkey org-columns-map [(shift meta right)] 'org-columns-new)
+(org-defkey org-columns-map [(shift meta left)] 'org-columns-delete)
+(dotimes (i 10)
+ (org-defkey org-columns-map (number-to-string i)
+ `(lambda () (interactive)
+ (org-columns-next-allowed-value nil ,i))))
+
+(easy-menu-define org-columns-menu org-columns-map "Org Column Menu"
+ '("Column"
+ ["Edit property" org-columns-edit-value t]
+ ["Next allowed value" org-columns-next-allowed-value t]
+ ["Previous allowed value" org-columns-previous-allowed-value t]
+ ["Show full value" org-columns-show-value t]
+ ["Edit allowed values" org-columns-edit-allowed t]
+ "--"
+ ["Edit column attributes" org-columns-edit-attributes t]
+ ["Increase column width" org-columns-widen t]
+ ["Decrease column width" org-columns-narrow t]
+ "--"
+ ["Move column right" org-columns-move-right t]
+ ["Move column left" org-columns-move-left t]
+ ["Add column" org-columns-new t]
+ ["Delete column" org-columns-delete t]
+ "--"
+ ["CONTENTS" org-columns-content t]
+ ["OVERVIEW" org-overview t]
+ ["Refresh columns display" org-columns-redo t]
+ "--"
+ ["Open link" org-columns-open-link t]
+ "--"
+ ["Quit" org-columns-quit t]))
+
+(defun org-columns-current-column ()
+ (if (featurep 'xemacs)
+ (/ (current-column) 2)
+ (current-column)))
+
+(defun org-columns-forward-char ()
+ (interactive)
+ (forward-char)
+ (if (featurep 'xemacs)
+ (while (not (or (eolp)
+ (member (extent-at
+ (point) (current-buffer)
+ 'org-columns-key) org-columns-overlays)))
+ (forward-char))))
+
+(defun org-columns-backward-char ()
+ (interactive)
+ (backward-char)
+ (if (featurep 'xemacs)
+ (while (not (or (bolp)
+ (member (extent-at (point) (current-buffer) 'org-columns-key) org-columns-overlays)))
+ (backward-char))))
+
+(defun org-columns-new-overlay (beg end &optional string face)
+ "Create a new column overlay and add it to the list."
+ (let ((ov (make-overlay beg end)))
+ (if (featurep 'xemacs)
+ (progn
+ (overlay-put ov 'face (or face 'org-columns-space1))
+ (overlay-put ov 'start-open t)
+ (if string
+ (org-overlay-display ov string (or face 'org-columns-space1))))
+ (overlay-put ov 'face (or face 'secondary-selection))
+ (org-overlay-display ov string face))
+ (push ov org-columns-overlays)
+ ov))
+
+(defun org-columns-display-here (&optional props)
+ "Overlay the current line with column display."
+ (interactive)
+ (let* ((fmt org-columns-current-fmt-compiled)
+ (beg (point-at-bol))
+ (level-face (save-excursion
+ (beginning-of-line 1)
+ (and (looking-at "\\(\\**\\)\\(\\* \\)")
+ (org-get-level-face 2))))
+ (item (save-match-data
+ (org-remove-tabs
+ (buffer-substring-no-properties
+ (point-at-bol) (point-at-eol)))))
+ (color (if (featurep 'xemacs)
+ (save-excursion
+ (beginning-of-line 1)
+ (and (looking-at "\\(\\**\\)\\(\\* \\)")
+ (org-get-columns-level-face 2)))
+ (list :foreground
+ (face-attribute
+ (or level-face
+ (and (eq major-mode 'org-agenda-mode)
+ (get-text-property (point-at-bol) 'face))
+ 'default) :foreground))))
+ (face (if (featurep 'xemacs) color (list color 'org-column)))
+ (pl (- (point)
+ (or (text-property-any (point-at-bol) (point-at-eol) 'org-heading t)
+ (point))))
+ (cphr (get-text-property (point-at-bol) 'org-complex-heading-regexp))
+ pom property ass width f string ov column val modval s2 title calc)
+ ;; Check if the entry is in another buffer.
+ (unless props
+ (if (eq major-mode 'org-agenda-mode)
+ (setq pom (or (org-get-at-bol 'org-hd-marker)
+ (org-get-at-bol 'org-marker))
+ props (if pom (org-entry-properties pom) nil))
+ (setq props (org-entry-properties nil))))
+ ;; Walk the format
+ (while (setq column (pop fmt))
+ (setq property (car column)
+ title (nth 1 column)
+ ass (if (equal property "ITEM")
+ (cons "ITEM" item)
+ (assoc property props))
+ width (or (cdr (assoc property org-columns-current-maxwidths))
+ (nth 2 column)
+ (length property))
+ f (format (if (featurep 'xemacs) "%%-%d.%ds |" "%%-%d.%ds | ")
+ width width)
+ val (or (cdr ass) "")
+ calc (nth 7 column)
+ modval (cond ((and org-columns-modify-value-for-display-function
+ (functionp
+ org-columns-modify-value-for-display-function))
+ (funcall org-columns-modify-value-for-display-function
+ title val))
+ ((equal property "ITEM")
+ (if (derived-mode-p 'org-mode)
+ (org-columns-cleanup-item
+ val org-columns-current-fmt-compiled)))
+ ((and calc (functionp calc)
+ (not (string= val ""))
+ (not (get-text-property 0 'org-computed val)))
+ (org-columns-number-to-string
+ (funcall calc (org-columns-string-to-number
+ val (nth 4 column)))
+ (nth 4 column)))))
+ (setq s2 (org-columns-add-ellipses (or modval val) width))
+ (setq string (format f s2))
+ ;; Create the overlay
+ (org-unmodified
+ (setq ov (org-columns-new-overlay
+ beg (setq beg (1+ beg)) string face))
+ (overlay-put ov 'keymap org-columns-map)
+ (overlay-put ov 'org-columns-key property)
+ (overlay-put ov 'org-columns-value (cdr ass))
+ (overlay-put ov 'org-columns-value-modified modval)
+ (overlay-put ov 'org-columns-pom pom)
+ (overlay-put ov 'org-columns-format f)
+ (when (featurep 'xemacs)
+ (if (or (not (char-after beg))
+ (equal (char-after beg) ?\n))
+ (let ((inhibit-read-only t))
+ (save-excursion
+ (goto-char beg)
+ (org-unmodified (insert " "))
+ ;; FIXME: add props and remove later?
+ )))
+ (goto-char beg)
+ (org-columns-new-overlay
+ beg (1+ beg) nil 'org-columns-space)
+ (setq beg (1+ beg))))
+
+ (if (or (not (char-after beg))
+ (equal (char-after beg) ?\n))
+ (let ((inhibit-read-only t))
+ (save-excursion
+ (goto-char beg)
+ ;; FIXME: add props and remove later?
+ (org-unmodified (insert " "))))))
+ ;; Make the rest of the line disappear.
+ (org-unmodified
+ (setq ov (org-columns-new-overlay beg (point-at-eol)))
+ (overlay-put ov 'invisible t)
+ (overlay-put ov 'keymap org-columns-map)
+ (overlay-put ov 'intangible t)
+ (push ov org-columns-overlays)
+ (setq ov (make-overlay (1- (point-at-eol)) (1+ (point-at-eol))))
+ (overlay-put ov 'keymap org-columns-map)
+ (push ov org-columns-overlays)
+ (let ((inhibit-read-only t))
+ (put-text-property (max (point-min) (1- (point-at-bol)))
+ (min (point-max) (1+ (point-at-eol)))
+ 'read-only "Type `e' to edit property")))))
+
+(defun org-columns-add-ellipses (string width)
+ "Truncate STRING with WIDTH characters, with ellipses."
+ (cond
+ ((<= (length string) width) string)
+ ((<= width (length org-columns-ellipses))
+ (substring org-columns-ellipses 0 width))
+ (t (concat (substring string 0 (- width (length org-columns-ellipses)))
+ org-columns-ellipses))))
+
+(defvar org-columns-full-header-line-format nil
+ "The full header line format, will be shifted by horizontal scrolling." )
+(defvar org-previous-header-line-format nil
+ "The header line format before column view was turned on.")
+(defvar org-columns-inhibit-recalculation nil
+ "Inhibit recomputing of columns on column view startup.")
+
+
+(defvar header-line-format)
+(defvar org-columns-previous-hscroll 0)
+
+(defun org-columns-display-here-title ()
+ "Overlay the newline before the current line with the table title."
+ (interactive)
+ (let ((fmt org-columns-current-fmt-compiled)
+ string (title "")
+ property width f column str widths)
+ (while (setq column (pop fmt))
+ (setq property (car column)
+ str (or (nth 1 column) property)
+ width (or (cdr (assoc property org-columns-current-maxwidths))
+ (nth 2 column)
+ (length str))
+ widths (push width widths)
+ f (format "%%-%d.%ds | " width width)
+ string (format f str)
+ title (concat title string)))
+ (if (featurep 'xemacs)
+ (let ((ext (make-extent nil nil)))
+ (set-extent-endpoints ext 0 (length title) title)
+ (set-extent-face ext (list 'bold 'underline 'org-columns-space1))
+ (org-set-local 'org-previous-header-line-format
+ (specifier-specs top-gutter))
+ (org-set-local 'org-columns-current-widths (nreverse widths))
+ (set-specifier top-gutter (make-gutter-specifier
+ (cons (current-buffer) title))))
+ (setq title (concat
+ (org-add-props " " nil 'display '(space :align-to 0))
+ (org-add-props title nil 'face '(:weight bold :underline t))))
+ (org-set-local 'org-previous-header-line-format header-line-format)
+ (org-set-local 'org-columns-current-widths (nreverse widths))
+ (setq org-columns-full-header-line-format title)
+ (setq org-columns-previous-hscroll -1)
+ (org-add-hook 'post-command-hook 'org-columns-hscoll-title nil 'local))))
+
+(defun org-columns-hscoll-title ()
+ "Set the `header-line-format' so that it scrolls along with the table."
+ (sit-for .0001) ; need to force a redisplay to update window-hscroll
+ (when (not (= (window-hscroll) org-columns-previous-hscroll))
+ (setq header-line-format
+ (concat (substring org-columns-full-header-line-format 0 1)
+ (substring org-columns-full-header-line-format
+ (1+ (window-hscroll))))
+ org-columns-previous-hscroll (window-hscroll))
+ (force-mode-line-update)))
+
+(defvar org-colview-initial-truncate-line-value nil
+ "Remember the value of `truncate-lines' across colview.")
+
+(defun org-columns-remove-overlays ()
+ "Remove all currently active column overlays."
+ (interactive)
+ (when (marker-buffer org-columns-begin-marker)
+ (with-current-buffer (marker-buffer org-columns-begin-marker)
+ (when (local-variable-p 'org-previous-header-line-format (current-buffer))
+ (if (featurep 'xemacs)
+ (set-specifier top-gutter
+ (make-gutter-specifier
+ (cons (current-buffer)
+ (cdar org-previous-header-line-format))))
+ (setq header-line-format org-previous-header-line-format)
+ (remove-hook 'post-command-hook 'org-columns-hscoll-title 'local))
+ (kill-local-variable 'org-previous-header-line-format))
+ (move-marker org-columns-begin-marker nil)
+ (move-marker org-columns-top-level-marker nil)
+ (org-unmodified
+ (mapc 'delete-overlay org-columns-overlays)
+ (setq org-columns-overlays nil)
+ (let ((inhibit-read-only t))
+ (remove-text-properties (point-min) (point-max) '(read-only t))))
+ (when (local-variable-p 'org-colview-initial-truncate-line-value
+ (current-buffer))
+ (setq truncate-lines org-colview-initial-truncate-line-value)))))
+
+
+(defun org-columns-cleanup-item (item fmt)
+ "Remove from ITEM what is a column in the format FMT."
+ (if (not org-complex-heading-regexp)
+ item
+ (when (string-match org-complex-heading-regexp item)
+ (setq item
+ (concat
+ (org-add-props (match-string 1 item) nil
+ 'org-whitespace (* 2 (1- (org-reduced-level (- (match-end 1) (match-beginning 1))))))
+ (and (match-end 2) (not (assoc "TODO" fmt)) (concat " " (match-string 2 item)))
+ (and (match-end 3) (not (assoc "PRIORITY" fmt)) (concat " " (match-string 3 item)))
+ " " (save-match-data (org-columns-compact-links (or (match-string 4 item) "")))
+ (and (match-end 5) (not (assoc "TAGS" fmt)) (concat " " (match-string 5 item)))))
+ (add-text-properties
+ 0 (1+ (match-end 1))
+ (list 'org-whitespace (* 2 (1- (org-reduced-level (- (match-end 1) (match-beginning 1))))))
+ item)
+ item)))
+
+(defun org-columns-compact-links (s)
+ "Replace [[link][desc]] with [desc] or [link]."
+ (while (string-match org-bracket-link-regexp s)
+ (setq s (replace-match
+ (concat "[" (match-string (if (match-end 3) 3 1) s) "]")
+ t t s)))
+ s)
+
+(defun org-columns-show-value ()
+ "Show the full value of the property."
+ (interactive)
+ (let ((value (get-char-property (point) 'org-columns-value)))
+ (message "Value is: %s" (or value ""))))
+
+(defvar org-agenda-columns-active) ;; defined in org-agenda.el
+
+(defun org-columns-quit ()
+ "Remove the column overlays and in this way exit column editing."
+ (interactive)
+ (org-unmodified
+ (org-columns-remove-overlays)
+ (let ((inhibit-read-only t))
+ (remove-text-properties (point-min) (point-max) '(read-only t))))
+ (when (eq major-mode 'org-agenda-mode)
+ (setq org-agenda-columns-active nil)
+ (message
+ "Modification not yet reflected in Agenda buffer, use `r' to refresh")))
+
+(defun org-columns-check-computed ()
+ "Check if this column value is computed.
+If yes, throw an error indicating that changing it does not make sense."
+ (let ((val (get-char-property (point) 'org-columns-value)))
+ (when (and (stringp val)
+ (get-char-property 0 'org-computed val))
+ (error "This value is computed from the entry's children"))))
+
+(defun org-columns-todo (&optional arg)
+ "Change the TODO state during column view."
+ (interactive "P")
+ (org-columns-edit-value "TODO"))
+
+(defun org-columns-set-tags-or-toggle (&optional arg)
+ "Toggle checkbox at point, or set tags for current headline."
+ (interactive "P")
+ (if (string-match "\\`\\[[ xX-]\\]\\'"
+ (get-char-property (point) 'org-columns-value))
+ (org-columns-next-allowed-value)
+ (org-columns-edit-value "TAGS")))
+
+(defun org-columns-edit-value (&optional key)
+ "Edit the value of the property at point in column view.
+Where possible, use the standard interface for changing this line."
+ (interactive)
+ (org-columns-check-computed)
+ (let* ((col (current-column))
+ (key (or key (get-char-property (point) 'org-columns-key)))
+ (value (get-char-property (point) 'org-columns-value))
+ (bol (point-at-bol)) (eol (point-at-eol))
+ (pom (or (get-text-property bol 'org-hd-marker)
+ (point))) ; keep despite of compiler warning
+ (line-overlays
+ (delq nil (mapcar (lambda (x)
+ (and (eq (overlay-buffer x) (current-buffer))
+ (>= (overlay-start x) bol)
+ (<= (overlay-start x) eol)
+ x))
+ org-columns-overlays)))
+ (org-columns-time (time-to-number-of-days (current-time)))
+ nval eval allowed)
+ (cond
+ ((equal key "CLOCKSUM")
+ (error "This special column cannot be edited"))
+ ((equal key "ITEM")
+ (setq eval '(org-with-point-at pom (org-edit-headline))))
+ ((equal key "TODO")
+ (setq eval '(org-with-point-at
+ pom
+ (call-interactively 'org-todo))))
+ ((equal key "PRIORITY")
+ (setq eval '(org-with-point-at pom
+ (call-interactively 'org-priority))))
+ ((equal key "TAGS")
+ (setq eval '(org-with-point-at
+ pom
+ (let ((org-fast-tag-selection-single-key
+ (if (eq org-fast-tag-selection-single-key 'expert)
+ t org-fast-tag-selection-single-key)))
+ (call-interactively 'org-set-tags)))))
+ ((equal key "DEADLINE")
+ (setq eval '(org-with-point-at
+ pom
+ (call-interactively 'org-deadline))))
+ ((equal key "SCHEDULED")
+ (setq eval '(org-with-point-at
+ pom
+ (call-interactively 'org-schedule))))
+ (t
+ (setq allowed (org-property-get-allowed-values pom key 'table))
+ (if allowed
+ (setq nval (org-icompleting-read
+ "Value: " allowed nil
+ (not (get-text-property 0 'org-unrestricted
+ (caar allowed)))))
+ (setq nval (read-string "Edit: " value)))
+ (setq nval (org-trim nval))
+ (when (not (equal nval value))
+ (setq eval '(org-entry-put pom key nval)))))
+ (when eval
+
+ (cond
+ ((equal major-mode 'org-agenda-mode)
+ (org-columns-eval eval)
+ ;; The following let preserves the current format, and makes sure
+ ;; that in only a single file things need to be upated.
+ (let* ((org-agenda-overriding-columns-format org-columns-current-fmt)
+ (buffer (marker-buffer pom))
+ (org-agenda-contributing-files
+ (list (with-current-buffer buffer
+ (buffer-file-name (buffer-base-buffer))))))
+ (org-agenda-columns)))
+ (t
+ (let ((inhibit-read-only t))
+ (org-unmodified
+ (remove-text-properties
+ (max (point-min) (1- bol)) eol '(read-only t)))
+ (unwind-protect
+ (progn
+ (setq org-columns-overlays
+ (org-delete-all line-overlays org-columns-overlays))
+ (mapc 'delete-overlay line-overlays)
+ (org-columns-eval eval))
+ (org-columns-display-here)))
+ (org-move-to-column col)
+ (if (and (derived-mode-p 'org-mode)
+ (nth 3 (assoc key org-columns-current-fmt-compiled)))
+ (org-columns-update key)))))))
+
+(defun org-edit-headline () ; FIXME: this is not columns specific. Make interactive????? Use from agenda????
+ "Edit the current headline, the part without TODO keyword, TAGS."
+ (org-back-to-heading)
+ (when (looking-at org-todo-line-regexp)
+ (let ((pos (point))
+ (pre (buffer-substring (match-beginning 0) (match-beginning 3)))
+ (txt (match-string 3))
+ (post "")
+ txt2)
+ (if (string-match (org-re "[ \t]+:[[:alnum:]:_@#%]+:[ \t]*$") txt)
+ (setq post (match-string 0 txt)
+ txt (substring txt 0 (match-beginning 0))))
+ (setq txt2 (read-string "Edit: " txt))
+ (when (not (equal txt txt2))
+ (goto-char pos)
+ (insert pre txt2 post)
+ (delete-region (point) (point-at-eol))
+ (org-set-tags nil t)))))
+
+(defun org-columns-edit-allowed ()
+ "Edit the list of allowed values for the current property."
+ (interactive)
+ (let* ((pom (or (org-get-at-bol 'org-marker)
+ (org-get-at-bol 'org-hd-marker)
+ (point)))
+ (key (get-char-property (point) 'org-columns-key))
+ (key1 (concat key "_ALL"))
+ (allowed (org-entry-get pom key1 t))
+ nval)
+ ;; FIXME: Cover editing TODO, TAGS etc in-buffer settings.????
+ ;; FIXME: Write back to #+PROPERTY setting if that is needed.
+ (setq nval (read-string "Allowed: " allowed))
+ (org-entry-put
+ (cond ((marker-position org-entry-property-inherited-from)
+ org-entry-property-inherited-from)
+ ((marker-position org-columns-top-level-marker)
+ org-columns-top-level-marker)
+ (t pom))
+ key1 nval)))
+
+(defun org-columns-eval (form)
+ (let (hidep)
+ (save-excursion
+ (beginning-of-line 1)
+ ;; `next-line' is needed here, because it skips invisible line.
+ (condition-case nil (org-no-warnings (next-line 1)) (error nil))
+ (setq hidep (org-at-heading-p 1)))
+ (eval form)
+ (and hidep (hide-entry))))
+
+(defun org-columns-previous-allowed-value ()
+ "Switch to the previous allowed value for this column."
+ (interactive)
+ (org-columns-next-allowed-value t))
+
+(defun org-columns-next-allowed-value (&optional previous nth)
+ "Switch to the next allowed value for this column.
+When PREVIOUS is set, go to the previous value. When NTH is
+an integer, select that value."
+ (interactive)
+ (org-columns-check-computed)
+ (let* ((col (current-column))
+ (key (get-char-property (point) 'org-columns-key))
+ (value (get-char-property (point) 'org-columns-value))
+ (bol (point-at-bol)) (eol (point-at-eol))
+ (pom (or (get-text-property bol 'org-hd-marker)
+ (point))) ; keep despite of compiler waring
+ (line-overlays
+ (delq nil (mapcar (lambda (x)
+ (and (eq (overlay-buffer x) (current-buffer))
+ (>= (overlay-start x) bol)
+ (<= (overlay-start x) eol)
+ x))
+ org-columns-overlays)))
+ (allowed (or (org-property-get-allowed-values pom key)
+ (and (memq
+ (nth 4 (assoc key org-columns-current-fmt-compiled))
+ '(checkbox checkbox-n-of-m checkbox-percent))
+ '("[ ]" "[X]"))
+ (org-colview-construct-allowed-dates value)))
+ nval)
+ (when (integerp nth)
+ (setq nth (1- nth))
+ (if (= nth -1) (setq nth 9)))
+ (when (equal key "ITEM")
+ (error "Cannot edit item headline from here"))
+ (unless (or allowed (member key '("SCHEDULED" "DEADLINE")))
+ (error "Allowed values for this property have not been defined"))
+ (if (member key '("SCHEDULED" "DEADLINE"))
+ (setq nval (if previous 'earlier 'later))
+ (if previous (setq allowed (reverse allowed)))
+ (cond
+ (nth
+ (setq nval (nth nth allowed))
+ (if (not nval)
+ (error "There are only %d allowed values for property `%s'"
+ (length allowed) key)))
+ ((member value allowed)
+ (setq nval (or (car (cdr (member value allowed)))
+ (car allowed)))
+ (if (equal nval value)
+ (error "Only one allowed value for this property")))
+ (t (setq nval (car allowed)))))
+ (cond
+ ((equal major-mode 'org-agenda-mode)
+ (org-columns-eval '(org-entry-put pom key nval))
+ ;; The following let preserves the current format, and makes sure
+ ;; that in only a single file things need to be upated.
+ (let* ((org-agenda-overriding-columns-format org-columns-current-fmt)
+ (buffer (marker-buffer pom))
+ (org-agenda-contributing-files
+ (list (with-current-buffer buffer
+ (buffer-file-name (buffer-base-buffer))))))
+ (org-agenda-columns)))
+ (t
+ (let ((inhibit-read-only t))
+ (remove-text-properties (1- bol) eol '(read-only t))
+ (unwind-protect
+ (progn
+ (setq org-columns-overlays
+ (org-delete-all line-overlays org-columns-overlays))
+ (mapc 'delete-overlay line-overlays)
+ (org-columns-eval '(org-entry-put pom key nval)))
+ (org-columns-display-here)))
+ (org-move-to-column col)
+ (and (nth 3 (assoc key org-columns-current-fmt-compiled))
+ (org-columns-update key))))))
+
+(defun org-colview-construct-allowed-dates (s)
+ "Construct a list of three dates around the date in S.
+This respects the format of the time stamp in S, active or non-active,
+and also including time or not. S must be just a time stamp, no text
+around it."
+ (when (and s (string-match (concat "^" org-ts-regexp3 "$") s))
+ (let* ((time (org-parse-time-string s 'nodefaults))
+ (active (equal (string-to-char s) ?<))
+ (fmt (funcall (if (nth 1 time) 'cdr 'car) org-time-stamp-formats))
+ time-before time-after)
+ (unless active (setq fmt (concat "[" (substring fmt 1 -1) "]")))
+ (setf (car time) (or (car time) 0))
+ (setf (nth 1 time) (or (nth 1 time) 0))
+ (setf (nth 2 time) (or (nth 2 time) 0))
+ (setq time-before (copy-sequence time))
+ (setq time-after (copy-sequence time))
+ (setf (nth 3 time-before) (1- (nth 3 time)))
+ (setf (nth 3 time-after) (1+ (nth 3 time)))
+ (mapcar (lambda (x) (format-time-string fmt (apply 'encode-time x)))
+ (list time-before time time-after)))))
+
+(defun org-verify-version (task)
+ (cond
+ ((eq task 'columns)
+ (if (or (and (featurep 'xemacs) (not (featurep 'org-colview-xemacs)))
+ (and (not (featurep 'xemacs)) (< emacs-major-version 22)))
+ (error "This version of Emacs cannot run Column View")))))
+
+(defun org-columns-open-link (&optional arg)
+ (interactive "P")
+ (let ((value (get-char-property (point) 'org-columns-value)))
+ (org-open-link-from-string value arg)))
+
+(defun org-columns-get-format-and-top-level ()
+ (let (fmt)
+ (when (condition-case nil (org-back-to-heading) (error nil))
+ (setq fmt (org-entry-get nil "COLUMNS" t)))
+ (setq fmt (or fmt org-columns-default-format))
+ (org-set-local 'org-columns-current-fmt fmt)
+ (org-columns-compile-format fmt)
+ (if (marker-position org-entry-property-inherited-from)
+ (move-marker org-columns-top-level-marker
+ org-entry-property-inherited-from)
+ (move-marker org-columns-top-level-marker (point)))
+ fmt))
+
+(defun org-columns ()
+ "Turn on column view on an org-mode file."
+ (interactive)
+ (org-verify-version 'columns)
+ (when (featurep 'xemacs)
+ (set-face-foreground 'org-columns-space
+ (face-background 'org-columns-space)))
+ (org-columns-remove-overlays)
+ (move-marker org-columns-begin-marker (point))
+ (let ((org-columns-time (time-to-number-of-days (current-time)))
+ beg end fmt cache maxwidths)
+ (setq fmt (org-columns-get-format-and-top-level))
+ (save-excursion
+ (goto-char org-columns-top-level-marker)
+ (setq beg (point))
+ (unless org-columns-inhibit-recalculation
+ (org-columns-compute-all))
+ (setq end (or (condition-case nil (org-end-of-subtree t t) (error nil))
+ (point-max)))
+ ;; Get and cache the properties
+ (goto-char beg)
+ (when (assoc "CLOCKSUM" org-columns-current-fmt-compiled)
+ (save-excursion
+ (save-restriction
+ (narrow-to-region beg end)
+ (org-clock-sum))))
+ (while (re-search-forward org-outline-regexp-bol end t)
+ (if (and org-columns-skip-archived-trees
+ (looking-at (concat ".*:" org-archive-tag ":")))
+ (org-end-of-subtree t)
+ (push (cons (org-current-line) (org-entry-properties)) cache)))
+ (when cache
+ (setq maxwidths (org-columns-get-autowidth-alist fmt cache))
+ (org-set-local 'org-columns-current-maxwidths maxwidths)
+ (org-columns-display-here-title)
+ (unless (local-variable-p 'org-colview-initial-truncate-line-value
+ (current-buffer))
+ (org-set-local 'org-colview-initial-truncate-line-value
+ truncate-lines))
+ (setq truncate-lines t)
+ (mapc (lambda (x)
+ (org-goto-line (car x))
+ (org-columns-display-here (cdr x)))
+ cache)))))
+
+(eval-when-compile (defvar org-columns-time))
+
+(defvar org-columns-compile-map
+ '(("none" none +)
+ (":" add_times +)
+ ("+" add_numbers +)
+ ("$" currency +)
+ ("X" checkbox +)
+ ("X/" checkbox-n-of-m +)
+ ("X%" checkbox-percent +)
+ ("max" max_numbers max)
+ ("min" min_numbers min)
+ ("mean" mean_numbers
+ (lambda (&rest x) (/ (apply '+ x) (float (length x)))))
+ (":max" max_times max)
+ (":min" min_times min)
+ (":mean" mean_times
+ (lambda (&rest x) (/ (apply '+ x) (float (length x)))))
+ ("@min" min_age min (lambda (x) (- org-columns-time x)))
+ ("@max" max_age max (lambda (x) (- org-columns-time x)))
+ ("@mean" mean_age
+ (lambda (&rest x) (/ (apply '+ x) (float (length x))))
+ (lambda (x) (- org-columns-time x)))
+ ("est+" estimate org-estimate-combine))
+ "Operator <-> format,function,calc map.
+Used to compile/uncompile columns format and completing read in
+interactive function `org-columns-new'.
+
+ operator string used in #+COLUMNS definition describing the
+ summary type
+ format symbol describing summary type selected interactively in
+ `org-columns-new' and internally in
+ `org-columns-number-to-string' and
+ `org-columns-string-to-number'
+ function called with a list of values as argument to calculate
+ the summary value
+ calc function called on every element before summarizing. This is
+ optional and should only be specified if needed")
+
+
+(defun org-columns-new (&optional prop title width op fmt fun &rest rest)
+ "Insert a new column, to the left of the current column."
+ (interactive)
+ (let ((n (org-columns-current-column))
+ (editp (and prop (assoc prop org-columns-current-fmt-compiled)))
+ cell)
+ (setq prop (org-icompleting-read
+ "Property: " (mapcar 'list (org-buffer-property-keys t nil t))
+ nil nil prop))
+ (setq title (read-string (concat "Column title [" prop "]: ") (or title prop)))
+ (setq width (read-string "Column width: " (if width (number-to-string width))))
+ (if (string-match "\\S-" width)
+ (setq width (string-to-number width))
+ (setq width nil))
+ (setq fmt (org-icompleting-read "Summary [none]: "
+ (mapcar (lambda (x) (list (symbol-name (cadr x)))) org-columns-compile-map)
+ nil t))
+ (setq fmt (intern fmt)
+ fun (cdr (assoc fmt (mapcar 'cdr org-columns-compile-map))))
+ (if (eq fmt 'none) (setq fmt nil))
+ (if editp
+ (progn
+ (setcar editp prop)
+ (setcdr editp (list title width nil fmt nil fun)))
+ (setq cell (nthcdr (1- n) org-columns-current-fmt-compiled))
+ (setcdr cell (cons (list prop title width nil fmt nil
+ (car fun) (cadr fun))
+ (cdr cell))))
+ (org-columns-store-format)
+ (org-columns-redo)))
+
+(defun org-columns-delete ()
+ "Delete the column at point from columns view."
+ (interactive)
+ (let* ((n (org-columns-current-column))
+ (title (nth 1 (nth n org-columns-current-fmt-compiled))))
+ (when (y-or-n-p
+ (format "Are you sure you want to remove column \"%s\"? " title))
+ (setq org-columns-current-fmt-compiled
+ (delq (nth n org-columns-current-fmt-compiled)
+ org-columns-current-fmt-compiled))
+ (org-columns-store-format)
+ (org-columns-redo)
+ (if (>= (org-columns-current-column)
+ (length org-columns-current-fmt-compiled))
+ (org-columns-backward-char)))))
+
+(defun org-columns-edit-attributes ()
+ "Edit the attributes of the current column."
+ (interactive)
+ (let* ((n (org-columns-current-column))
+ (info (nth n org-columns-current-fmt-compiled)))
+ (apply 'org-columns-new info)))
+
+(defun org-columns-widen (arg)
+ "Make the column wider by ARG characters."
+ (interactive "p")
+ (let* ((n (org-columns-current-column))
+ (entry (nth n org-columns-current-fmt-compiled))
+ (width (or (nth 2 entry)
+ (cdr (assoc (car entry) org-columns-current-maxwidths)))))
+ (setq width (max 1 (+ width arg)))
+ (setcar (nthcdr 2 entry) width)
+ (org-columns-store-format)
+ (org-columns-redo)))
+
+(defun org-columns-narrow (arg)
+ "Make the column narrower by ARG characters."
+ (interactive "p")
+ (org-columns-widen (- arg)))
+
+(defun org-columns-move-right ()
+ "Swap this column with the one to the right."
+ (interactive)
+ (let* ((n (org-columns-current-column))
+ (cell (nthcdr n org-columns-current-fmt-compiled))
+ e)
+ (when (>= n (1- (length org-columns-current-fmt-compiled)))
+ (error "Cannot shift this column further to the right"))
+ (setq e (car cell))
+ (setcar cell (car (cdr cell)))
+ (setcdr cell (cons e (cdr (cdr cell))))
+ (org-columns-store-format)
+ (org-columns-redo)
+ (org-columns-forward-char)))
+
+(defun org-columns-move-left ()
+ "Swap this column with the one to the left."
+ (interactive)
+ (let* ((n (org-columns-current-column)))
+ (when (= n 0)
+ (error "Cannot shift this column further to the left"))
+ (org-columns-backward-char)
+ (org-columns-move-right)
+ (org-columns-backward-char)))
+
+(defun org-columns-store-format ()
+ "Store the text version of the current columns format in appropriate place.
+This is either in the COLUMNS property of the node starting the current column
+display, or in the #+COLUMNS line of the current buffer."
+ (let (fmt (cnt 0))
+ (setq fmt (org-columns-uncompile-format org-columns-current-fmt-compiled))
+ (org-set-local 'org-columns-current-fmt fmt)
+ (if (marker-position org-columns-top-level-marker)
+ (save-excursion
+ (goto-char org-columns-top-level-marker)
+ (if (and (org-at-heading-p)
+ (org-entry-get nil "COLUMNS"))
+ (org-entry-put nil "COLUMNS" fmt)
+ (goto-char (point-min))
+ ;; Overwrite all #+COLUMNS lines....
+ (while (re-search-forward "^#\\+COLUMNS:.*" nil t)
+ (setq cnt (1+ cnt))
+ (replace-match (concat "#+COLUMNS: " fmt) t t))
+ (unless (> cnt 0)
+ (goto-char (point-min))
+ (or (org-at-heading-p t) (outline-next-heading))
+ (let ((inhibit-read-only t))
+ (insert-before-markers "#+COLUMNS: " fmt "\n")))
+ (org-set-local 'org-columns-default-format fmt))))))
+
+(defvar org-agenda-overriding-columns-format nil
+ "When set, overrides any other format definition for the agenda.
+Don't set this, this is meant for dynamic scoping.")
+
+(defun org-columns-get-autowidth-alist (s cache)
+ "Derive the maximum column widths from the format and the cache."
+ (let ((start 0) rtn)
+ (while (string-match (org-re "%\\([[:alpha:]][[:alnum:]_-]*\\)") s start)
+ (push (cons (match-string 1 s) 1) rtn)
+ (setq start (match-end 0)))
+ (mapc (lambda (x)
+ (setcdr x (apply 'max
+ (mapcar
+ (lambda (y)
+ (length (or (cdr (assoc (car x) (cdr y))) " ")))
+ cache))))
+ rtn)
+ rtn))
+
+(defun org-columns-compute-all ()
+ "Compute all columns that have operators defined."
+ (org-unmodified
+ (remove-text-properties (point-min) (point-max) '(org-summaries t)))
+ (let ((columns org-columns-current-fmt-compiled)
+ (org-columns-time (time-to-number-of-days (current-time)))
+ col)
+ (while (setq col (pop columns))
+ (when (nth 3 col)
+ (save-excursion
+ (org-columns-compute (car col)))))))
+
+(defun org-columns-update (property)
+ "Recompute PROPERTY, and update the columns display for it."
+ (org-columns-compute property)
+ (let (fmt val pos face)
+ (save-excursion
+ (mapc (lambda (ov)
+ (when (equal (overlay-get ov 'org-columns-key) property)
+ (setq pos (overlay-start ov))
+ (goto-char pos)
+ (when (setq val (cdr (assoc property
+ (get-text-property
+ (point-at-bol) 'org-summaries))))
+ (setq fmt (overlay-get ov 'org-columns-format))
+ (overlay-put ov 'org-columns-value val)
+ (if (featurep 'xemacs)
+ (progn
+ (setq face (glyph-face (extent-end-glyph ov)))
+ (org-overlay-display ov (format fmt val) face))
+ (org-overlay-display ov (format fmt val))))))
+ org-columns-overlays))))
+
+(defun org-columns-compute (property)
+ "Sum the values of property PROPERTY hierarchically, for the entire buffer."
+ (interactive)
+ (let* ((re org-outline-regexp-bol)
+ (lmax 30) ; Does anyone use deeper levels???
+ (lvals (make-vector lmax nil))
+ (lflag (make-vector lmax nil))
+ (level 0)
+ (ass (assoc property org-columns-current-fmt-compiled))
+ (format (nth 4 ass))
+ (printf (nth 5 ass))
+ (fun (nth 6 ass))
+ (calc (or (nth 7 ass) 'identity))
+ (beg org-columns-top-level-marker)
+ last-level val valflag flag end sumpos sum-alist sum str str1 useval)
+ (save-excursion
+ ;; Find the region to compute
+ (goto-char beg)
+ (setq end (condition-case nil (org-end-of-subtree t) (error (point-max))))
+ (goto-char end)
+ ;; Walk the tree from the back and do the computations
+ (while (re-search-backward re beg t)
+ (setq sumpos (match-beginning 0)
+ last-level level
+ level (org-outline-level)
+ val (org-entry-get nil property)
+ valflag (and val (string-match "\\S-" val)))
+ (cond
+ ((< level last-level)
+ ;; put the sum of lower levels here as a property
+ (setq sum (when (aref lvals last-level)
+ (apply fun (aref lvals last-level)))
+ flag (aref lflag last-level) ; any valid entries from children?
+ str (org-columns-number-to-string sum format printf)
+ str1 (org-add-props (copy-sequence str) nil 'org-computed t 'face 'bold)
+ useval (if flag str1 (if valflag val ""))
+ sum-alist (get-text-property sumpos 'org-summaries))
+ (if (assoc property sum-alist)
+ (setcdr (assoc property sum-alist) useval)
+ (push (cons property useval) sum-alist)
+ (org-unmodified
+ (add-text-properties sumpos (1+ sumpos)
+ (list 'org-summaries sum-alist))))
+ (when (and val (not (equal val (if flag str val))))
+ (org-entry-put nil property (if flag str val)))
+ ;; add current to current level accumulator
+ (when (or flag valflag)
+ (push (if flag
+ sum
+ (funcall calc (org-columns-string-to-number
+ (if flag str val) format)))
+ (aref lvals level))
+ (aset lflag level t))
+ ;; clear accumulators for deeper levels
+ (loop for l from (1+ level) to (1- lmax) do
+ (aset lvals l nil)
+ (aset lflag l nil)))
+ ((>= level last-level)
+ ;; add what we have here to the accumulator for this level
+ (when valflag
+ (push (funcall calc (org-columns-string-to-number val format))
+ (aref lvals level))
+ (aset lflag level t)))
+ (t (error "This should not happen")))))))
+
+(defun org-columns-redo ()
+ "Construct the column display again."
+ (interactive)
+ (message "Recomputing columns...")
+ (save-excursion
+ (if (marker-position org-columns-begin-marker)
+ (goto-char org-columns-begin-marker))
+ (org-columns-remove-overlays)
+ (if (derived-mode-p 'org-mode)
+ (call-interactively 'org-columns)
+ (org-agenda-redo)
+ (call-interactively 'org-agenda-columns)))
+ (when (featurep 'xemacs)
+ (while (not (or (eolp)
+ (member (extent-at (point)) org-columns-overlays)))
+ (forward-char)))
+ (message "Recomputing columns...done"))
+
+(defun org-columns-not-in-agenda ()
+ (if (eq major-mode 'org-agenda-mode)
+ (error "This command is only allowed in Org-mode buffers")))
+
+(defun org-string-to-number (s)
+ "Convert string to number, and interpret hh:mm:ss."
+ (if (not (string-match ":" s))
+ (string-to-number s)
+ (let ((l (nreverse (org-split-string s ":"))) (sum 0.0))
+ (while l
+ (setq sum (+ (string-to-number (pop l)) (/ sum 60))))
+ sum)))
+
+(defun org-columns-number-to-string (n fmt &optional printf)
+ "Convert a computed column number to a string value, according to FMT."
+ (cond
+ ((memq fmt '(estimate)) (org-estimate-print n printf))
+ ((not (numberp n)) "")
+ ((memq fmt '(add_times max_times min_times mean_times))
+ (let* ((h (floor n)) (m (floor (+ 0.5 (* 60 (- n h))))))
+ (format org-time-clocksum-format h m)))
+ ((eq fmt 'checkbox)
+ (cond ((= n (floor n)) "[X]")
+ ((> n 1.) "[-]")
+ (t "[ ]")))
+ ((memq fmt '(checkbox-n-of-m checkbox-percent))
+ (let* ((n1 (floor n)) (n2 (floor (+ .5 (* 1000000 (- n n1))))))
+ (org-nofm-to-completion n1 (+ n2 n1) (eq fmt 'checkbox-percent))))
+ (printf (format printf n))
+ ((eq fmt 'currency)
+ (format "%.2f" n))
+ ((memq fmt '(min_age max_age mean_age))
+ (org-format-time-period n))
+ (t (number-to-string n))))
+
+(defun org-nofm-to-completion (n m &optional percent)
+ (if (not percent)
+ (format "[%d/%d]" n m)
+ (format "[%d%%]"(floor (+ 0.5 (* 100. (/ (* 1.0 n) m)))))))
+
+(defun org-columns-string-to-number (s fmt)
+ "Convert a column value to a number that can be used for column computing."
+ (if s
+ (cond
+ ((memq fmt '(min_age max_age mean_age))
+ (cond ((string= s "") org-columns-time)
+ ((string-match
+ "\\([0-9]+\\)d \\([0-9]+\\)h \\([0-9]+\\)m \\([0-9]+\\)s"
+ s)
+ (+ (* 60 (+ (* 60 (+ (* 24 (string-to-number (match-string 1 s)))
+ (string-to-number (match-string 2 s))))
+ (string-to-number (match-string 3 s))))
+ (string-to-number (match-string 4 s))))
+ (t (time-to-number-of-days (apply 'encode-time
+ (org-parse-time-string s t))))))
+ ((string-match ":" s)
+ (let ((l (nreverse (org-split-string s ":"))) (sum 0.0))
+ (while l
+ (setq sum (+ (string-to-number (pop l)) (/ sum 60))))
+ sum))
+ ((memq fmt '(checkbox checkbox-n-of-m checkbox-percent))
+ (if (equal s "[X]") 1. 0.000001))
+ ((memq fmt '(estimate)) (org-string-to-estimate s))
+ (t (string-to-number s)))))
+
+(defun org-columns-uncompile-format (cfmt)
+ "Turn the compiled columns format back into a string representation."
+ (let ((rtn "") e s prop title op op-match width fmt printf fun calc)
+ (while (setq e (pop cfmt))
+ (setq prop (car e)
+ title (nth 1 e)
+ width (nth 2 e)
+ op (nth 3 e)
+ fmt (nth 4 e)
+ printf (nth 5 e)
+ fun (nth 6 e)
+ calc (nth 7 e))
+ (when (setq op-match (rassoc (list fmt fun calc) org-columns-compile-map))
+ (setq op (car op-match)))
+ (if (and op printf) (setq op (concat op ";" printf)))
+ (if (equal title prop) (setq title nil))
+ (setq s (concat "%" (if width (number-to-string width))
+ prop
+ (if title (concat "(" title ")"))
+ (if op (concat "{" op "}"))))
+ (setq rtn (concat rtn " " s)))
+ (org-trim rtn)))
+
+(defun org-columns-compile-format (fmt)
+ "Turn a column format string into an alist of specifications.
+The alist has one entry for each column in the format. The elements of
+that list are:
+property the property
+title the title field for the columns
+width the column width in characters, can be nil for automatic
+operator the operator if any
+format the output format for computed results, derived from operator
+printf a printf format for computed values
+fun the lisp function to compute summary values, derived from operator
+calc function to get values from base elements"
+ (let ((start 0) width prop title op op-match f printf fun calc)
+ (setq org-columns-current-fmt-compiled nil)
+ (while (string-match
+ (org-re "%\\([0-9]+\\)?\\([[:alnum:]_-]+\\)\\(?:(\\([^)]+\\))\\)?\\(?:{\\([^}]+\\)}\\)?\\s-*")
+ fmt start)
+ (setq start (match-end 0)
+ width (match-string 1 fmt)
+ prop (match-string 2 fmt)
+ title (or (match-string 3 fmt) prop)
+ op (match-string 4 fmt)
+ f nil
+ printf nil
+ fun '+
+ calc nil)
+ (if width (setq width (string-to-number width)))
+ (when (and op (string-match ";" op))
+ (setq printf (substring op (match-end 0))
+ op (substring op 0 (match-beginning 0))))
+ (when (setq op-match (assoc op org-columns-compile-map))
+ (setq f (cadr op-match)
+ fun (caddr op-match)
+ calc (cadddr op-match)))
+ (push (list prop title width op f printf fun calc)
+ org-columns-current-fmt-compiled))
+ (setq org-columns-current-fmt-compiled
+ (nreverse org-columns-current-fmt-compiled))))
+
+
+;;; Dynamic block for Column view
+
+(defun org-columns-capture-view (&optional maxlevel skip-empty-rows)
+ "Get the column view of the current buffer or subtree.
+The first optional argument MAXLEVEL sets the level limit. A
+second optional argument SKIP-EMPTY-ROWS tells whether to skip
+empty rows, an empty row being one where all the column view
+specifiers except ITEM are empty. This function returns a list
+containing the title row and all other rows. Each row is a list
+of fields."
+ (if (featurep 'xemacs)
+ (save-excursion
+ (let* ((title (mapcar 'cadr org-columns-current-fmt-compiled))
+ (re-comment (format org-heading-keyword-regexp-format
+ org-comment-string))
+ (re-archive (concat ".*:" org-archive-tag ":"))
+ (n (length title)) row tbl)
+ (goto-char (point-min))
+
+ (while (re-search-forward org-heading-regexp nil t)
+ (catch 'next
+ (when (and (or (null maxlevel)
+ (>= maxlevel
+ (if org-odd-levels-only
+ (/ (1+ (length (match-string 1))) 2)
+ (length (match-string 1)))))
+ (get-char-property (match-beginning 0) 'org-columns-key))
+ (goto-char (match-beginning 0))
+ (when (save-excursion
+ (goto-char (point-at-bol))
+ (or (looking-at re-comment)
+ (looking-at re-archive)))
+ (org-end-of-subtree t)
+ (throw 'next t))
+ (setq row nil)
+ (loop for i from 0 to (1- n) do
+ (push
+ (org-quote-vert
+ (or (get-char-property (point)
+ 'org-columns-value-modified)
+ (get-char-property (point) 'org-columns-value)
+ ""))
+ row)
+ (org-columns-forward-char))
+ (setq row (nreverse row))
+ (unless (and skip-empty-rows
+ (eq 1 (length (delete "" (delete-dups (copy-sequence row))))))
+ (push row tbl)))))
+ (append (list title 'hline) (nreverse tbl))))
+ (save-excursion
+ (let* ((title (mapcar 'cadr org-columns-current-fmt-compiled))
+ (n (length title)) row tbl)
+ (goto-char (point-min))
+ (while (and (re-search-forward "^\\(\\*+\\) " nil t)
+ (or (null maxlevel)
+ (>= maxlevel
+ (if org-odd-levels-only
+ (/ (1+ (length (match-string 1))) 2)
+ (length (match-string 1))))))
+ (when (get-char-property (match-beginning 0) 'org-columns-key)
+ (setq row nil)
+ (loop for i from 0 to (1- n) do
+ (push (or (get-char-property (+ (match-beginning 0) i)
+ 'org-columns-value-modified)
+ (get-char-property (+ (match-beginning 0) i)
+ 'org-columns-value)
+ "")
+ row))
+ (setq row (nreverse row))
+ (unless (and skip-empty-rows
+ (eq 1 (length (delete "" (delete-dups row)))))
+ (push row tbl))))
+ (append (list title 'hline) (nreverse tbl))))))
+
+(defun org-dblock-write:columnview (params)
+ "Write the column view table.
+PARAMS is a property list of parameters:
+
+:width enforce same column widths with <N> specifiers.
+:id the :ID: property of the entry where the columns view
+ should be built. When the symbol `local', call locally.
+ When `global' call column view with the cursor at the beginning
+ of the buffer (usually this means that the whole buffer switches
+ to column view). When \"file:path/to/file.org\", invoke column
+ view at the start of that file. Otherwise, the ID is located
+ using `org-id-find'.
+:hlines When t, insert a hline before each item. When a number, insert
+ a hline before each level <= that number.
+:vlines When t, make each column a colgroup to enforce vertical lines.
+:maxlevel When set to a number, don't capture headlines below this level.
+:skip-empty-rows
+ When t, skip rows where all specifiers other than ITEM are empty."
+ (let ((pos (point-marker))
+ (hlines (plist-get params :hlines))
+ (vlines (plist-get params :vlines))
+ (maxlevel (plist-get params :maxlevel))
+ (content-lines (org-split-string (plist-get params :content) "\n"))
+ (skip-empty-rows (plist-get params :skip-empty-rows))
+ (case-fold-search t)
+ tbl id idpos nfields tmp recalc line
+ id-as-string view-file view-pos)
+ (when (setq id (plist-get params :id))
+ (setq id-as-string (cond ((numberp id) (number-to-string id))
+ ((symbolp id) (symbol-name id))
+ ((stringp id) id)
+ (t "")))
+ (cond ((not id) nil)
+ ((eq id 'global) (setq view-pos (point-min)))
+ ((eq id 'local))
+ ((string-match "^file:\\(.*\\)" id-as-string)
+ (setq view-file (match-string 1 id-as-string)
+ view-pos 1)
+ (unless (file-exists-p view-file)
+ (error "No such file: \"%s\"" id-as-string)))
+ ((setq idpos (org-find-entry-with-id id))
+ (setq view-pos idpos))
+ ((setq idpos (org-id-find id))
+ (setq view-file (car idpos))
+ (setq view-pos (cdr idpos)))
+ (t (error "Cannot find entry with :ID: %s" id))))
+ (with-current-buffer (if view-file
+ (get-file-buffer view-file)
+ (current-buffer))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (or view-pos (point)))
+ (org-columns)
+ (setq tbl (org-columns-capture-view maxlevel skip-empty-rows))
+ (setq nfields (length (car tbl)))
+ (org-columns-quit))))
+ (goto-char pos)
+ (move-marker pos nil)
+ (when tbl
+ (when (plist-get params :hlines)
+ (setq tmp nil)
+ (while tbl
+ (if (eq (car tbl) 'hline)
+ (push (pop tbl) tmp)
+ (if (string-match "\\` *\\(\\*+\\)" (caar tbl))
+ (if (and (not (eq (car tmp) 'hline))
+ (or (eq hlines t)
+ (and (numberp hlines)
+ (<= (- (match-end 1) (match-beginning 1))
+ hlines))))
+ (push 'hline tmp)))
+ (push (pop tbl) tmp)))
+ (setq tbl (nreverse tmp)))
+ (when vlines
+ (setq tbl (mapcar (lambda (x)
+ (if (eq 'hline x) x (cons "" x)))
+ tbl))
+ (setq tbl (append tbl (list (cons "/" (make-list nfields "<>"))))))
+ (setq pos (point))
+ (when content-lines
+ (while (string-match "^#" (car content-lines))
+ (insert (pop content-lines) "\n")))
+ (insert (org-listtable-to-string tbl))
+ (when (plist-get params :width)
+ (insert "\n|" (mapconcat (lambda (x) (format "<%d>" (max 3 x)))
+ org-columns-current-widths "|")))
+ (while (setq line (pop content-lines))
+ (when (string-match "^#" line)
+ (insert "\n" line)
+ (when (string-match "^[ \t]*#\\+tblfm" line)
+ (setq recalc t))))
+ (if recalc
+ (progn (goto-char pos) (org-table-recalculate 'all))
+ (goto-char pos)
+ (org-table-align)))))
+
+(defun org-listtable-to-string (tbl)
+ "Convert a listtable TBL to a string that contains the Org-mode table.
+The table still need to be aligned. The resulting string has no leading
+and tailing newline characters."
+ (mapconcat
+ (lambda (x)
+ (cond
+ ((listp x)
+ (concat "|" (mapconcat 'identity x "|") "|"))
+ ((eq x 'hline) "|-|")
+ (t (error "Garbage in listtable: %s" x))))
+ tbl "\n"))
+
+(defun org-insert-columns-dblock ()
+ "Create a dynamic block capturing a column view table."
+ (interactive)
+ (when (featurep 'xemacs) (org-columns-quit))
+ (let ((defaults '(:name "columnview" :hlines 1))
+ (id (org-icompleting-read
+ "Capture columns (local, global, entry with :ID: property) [local]: "
+ (append '(("global") ("local"))
+ (mapcar 'list (org-property-values "ID"))))))
+ (if (equal id "") (setq id 'local))
+ (if (equal id "global") (setq id 'global))
+ (setq defaults (append defaults (list :id id)))
+ (org-create-dblock defaults)
+ (org-update-dblock)))
+
+;;; Column view in the agenda
+
+(defvar org-agenda-view-columns-initially nil
+ "When set, switch to columns view immediately after creating the agenda.")
+
+(defvar org-agenda-columns-show-summaries) ; defined in org-agenda.el
+(defvar org-agenda-columns-compute-summary-properties); defined in org-agenda.el
+(defvar org-agenda-columns-add-appointments-to-effort-sum); as well
+
+(defun org-agenda-columns ()
+ "Turn on or update column view in the agenda."
+ (interactive)
+ (org-verify-version 'columns)
+ (org-columns-remove-overlays)
+ (move-marker org-columns-begin-marker (point))
+ (let ((org-columns-time (time-to-number-of-days (current-time)))
+ cache maxwidths m p a d fmt)
+ (cond
+ ((and (boundp 'org-agenda-overriding-columns-format)
+ org-agenda-overriding-columns-format)
+ (setq fmt org-agenda-overriding-columns-format)
+ (org-set-local 'org-agenda-overriding-columns-format fmt))
+ ((setq m (org-get-at-bol 'org-hd-marker))
+ (setq fmt (or (org-entry-get m "COLUMNS" t)
+ (with-current-buffer (marker-buffer m)
+ org-columns-default-format))))
+ ((and (boundp 'org-columns-current-fmt)
+ (local-variable-p 'org-columns-current-fmt (current-buffer))
+ org-columns-current-fmt)
+ (setq fmt org-columns-current-fmt))
+ ((setq m (next-single-property-change (point-min) 'org-hd-marker))
+ (setq m (get-text-property m 'org-hd-marker))
+ (setq fmt (or (org-entry-get m "COLUMNS" t)
+ (with-current-buffer (marker-buffer m)
+ org-columns-default-format)))))
+ (setq fmt (or fmt org-columns-default-format))
+ (org-set-local 'org-columns-current-fmt fmt)
+ (org-columns-compile-format fmt)
+ (when org-agenda-columns-compute-summary-properties
+ (org-agenda-colview-compute org-columns-current-fmt-compiled))
+ (save-excursion
+ ;; Get and cache the properties
+ (goto-char (point-min))
+ (while (not (eobp))
+ (when (setq m (or (org-get-at-bol 'org-hd-marker)
+ (org-get-at-bol 'org-marker)))
+ (setq p (org-entry-properties m))
+
+ (when (or (not (setq a (assoc org-effort-property p)))
+ (not (string-match "\\S-" (or (cdr a) ""))))
+ ;; OK, the property is not defined. Use appointment duration?
+ (when (and org-agenda-columns-add-appointments-to-effort-sum
+ (setq d (get-text-property (point) 'duration)))
+ (setq d (org-minutes-to-clocksum-string d))
+ (put-text-property 0 (length d) 'face 'org-warning d)
+ (push (cons org-effort-property d) p)))
+ (push (cons (org-current-line) p) cache))
+ (beginning-of-line 2))
+ (when cache
+ (setq maxwidths (org-columns-get-autowidth-alist fmt cache))
+ (org-set-local 'org-columns-current-maxwidths maxwidths)
+ (org-columns-display-here-title)
+ (mapc (lambda (x)
+ (org-goto-line (car x))
+ (org-columns-display-here (cdr x)))
+ cache)
+ (when org-agenda-columns-show-summaries
+ (org-agenda-colview-summarize cache))))))
+
+(defun org-agenda-colview-summarize (cache)
+ "Summarize the summarizable columns in column view in the agenda.
+This will add overlays to the date lines, to show the summary for each day."
+ (let* ((fmt (mapcar (lambda (x)
+ (if (equal (car x) "CLOCKSUM")
+ (list "CLOCKSUM" (nth 2 x) nil 'add_times nil '+ 'identity)
+ (cdr x)))
+ org-columns-current-fmt-compiled))
+ line c c1 stype calc sumfunc props lsum entries prop v)
+ (catch 'exit
+ (when (delq nil (mapcar 'cadr fmt))
+ ;; OK, at least one summation column, it makes sense to try this
+ (goto-char (point-max))
+ (while t
+ (when (or (get-text-property (point) 'org-date-line)
+ (eq (get-text-property (point) 'face)
+ 'org-agenda-structure))
+ ;; OK, this is a date line that should be used
+ (setq line (org-current-line))
+ (setq entries nil c cache cache nil)
+ (while (setq c1 (pop c))
+ (if (> (car c1) line)
+ (push c1 entries)
+ (push c1 cache)))
+ ;; now ENTRIES are the ones we want to use, CACHE is the rest
+ ;; Compute the summaries for the properties we want,
+ ;; set nil properties for the rest.
+ (when (setq entries (mapcar 'cdr entries))
+ (setq props
+ (mapcar
+ (lambda (f)
+ (setq prop (car f)
+ stype (nth 3 f)
+ sumfunc (nth 5 f)
+ calc (or (nth 6 f) 'identity))
+ (cond
+ ((equal prop "ITEM")
+ (cons prop (buffer-substring (point-at-bol)
+ (point-at-eol))))
+ ((not stype) (cons prop ""))
+ (t ;; do the summary
+ (setq lsum nil)
+ (dolist (x entries)
+ (setq v (cdr (assoc prop x)))
+ (if v
+ (push
+ (funcall
+ (if (not (get-text-property 0 'org-computed v))
+ calc
+ 'identity)
+ (org-columns-string-to-number
+ v stype))
+ lsum)))
+ (setq lsum (remove nil lsum))
+ (setq lsum
+ (cond ((> (length lsum) 1)
+ (org-columns-number-to-string
+ (apply sumfunc lsum) stype))
+ ((eq (length lsum) 1)
+ (org-columns-number-to-string
+ (car lsum) stype))
+ (t "")))
+ (put-text-property 0 (length lsum) 'face 'bold lsum)
+ (unless (eq calc 'identity)
+ (put-text-property 0 (length lsum) 'org-computed t lsum))
+ (cons prop lsum))))
+ fmt))
+ (org-columns-display-here props)
+ (org-set-local 'org-agenda-columns-active t)))
+ (if (bobp) (throw 'exit t))
+ (beginning-of-line 0))))))
+
+(defun org-agenda-colview-compute (fmt)
+ "Compute the relevant columns in the contributing source buffers."
+ (let ((files org-agenda-contributing-files)
+ (org-columns-begin-marker (make-marker))
+ (org-columns-top-level-marker (make-marker))
+ f fm a b)
+ (while (setq f (pop files))
+ (setq b (find-buffer-visiting f))
+ (with-current-buffer (or (buffer-base-buffer b) b)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (org-unmodified
+ (remove-text-properties (point-min) (point-max)
+ '(org-summaries t)))
+ (goto-char (point-min))
+ (org-columns-get-format-and-top-level)
+ (while (setq fm (pop fmt))
+ (if (equal (car fm) "CLOCKSUM")
+ (org-clock-sum)
+ (when (and (nth 4 fm)
+ (setq a (assoc (car fm)
+ org-columns-current-fmt-compiled))
+ (equal (nth 4 a) (nth 4 fm)))
+ (org-columns-compute (car fm)))))))))))
+
+(defun org-format-time-period (interval)
+ "Convert time in fractional days to days/hours/minutes/seconds."
+ (if (numberp interval)
+ (let* ((days (floor interval))
+ (frac-hours (* 24 (- interval days)))
+ (hours (floor frac-hours))
+ (minutes (floor (* 60 (- frac-hours hours))))
+ (seconds (floor (* 60 (- (* 60 (- frac-hours hours)) minutes)))))
+ (format "%dd %02dh %02dm %02ds" days hours minutes seconds))
+ ""))
+
+(defun org-estimate-mean-and-var (v)
+ "Return the mean and variance of an estimate."
+ (let* ((low (float (car v)))
+ (high (float (cadr v)))
+ (mean (/ (+ low high) 2.0))
+ (var (/ (+ (expt (- mean low) 2.0) (expt (- high mean) 2.0)) 2.0)))
+ (list mean var)))
+
+(defun org-estimate-combine (&rest el)
+ "Combine a list of estimates, using mean and variance.
+The mean and variance of the result will be the sum of the means
+and variances (respectively) of the individual estimates."
+ (let ((mean 0)
+ (var 0))
+ (mapc (lambda (e)
+ (let ((stats (org-estimate-mean-and-var e)))
+ (setq mean (+ mean (car stats)))
+ (setq var (+ var (cadr stats)))))
+ el)
+ (let ((stdev (sqrt var)))
+ (list (- mean stdev) (+ mean stdev)))))
+
+(defun org-estimate-print (e &optional fmt)
+ "Prepare a string representation of an estimate.
+This formats these numbers as two numbers with a \"-\" between them."
+ (if (null fmt) (set 'fmt "%.0f"))
+ (format "%s" (mapconcat (lambda (n) (format fmt n)) e "-")))
+
+(defun org-string-to-estimate (s)
+ "Convert a string to an estimate.
+The string should be two numbers joined with a \"-\"."
+ (if (string-match "\\(.*\\)-\\(.*\\)" s)
+ (list (string-to-number (match-string 1 s))
+ (string-to-number(match-string 2 s)))
+ (list (string-to-number s) (string-to-number s))))
+
+(provide 'org-colview)
+(provide 'org-colview-xemacs)
+
+;;; org-colview-xemacs.el ends here
diff --git a/contrib/lisp/org-contacts.el b/contrib/lisp/org-contacts.el
index bc52648..a3c4aed 100644
--- a/contrib/lisp/org-contacts.el
+++ b/contrib/lisp/org-contacts.el
@@ -1,18 +1,18 @@
;;; org-contacts.el --- Contacts management
-;; Copyright (C) 2010-2012 Julien Danjou <julien@danjou.info>
+;; Copyright (C) 2010-2013 Julien Danjou <julien@danjou.info>
;; Author: Julien Danjou <julien@danjou.info>
;; Keywords: outlines, hypermedia, calendar
;;
;; This file is NOT part of GNU Emacs.
;;
-;; GNU Emacs is free software: you can redistribute it and/or modify
+;; 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.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
@@ -39,17 +39,20 @@
(eval-when-compile
(require 'cl))
-(eval-and-compile
- (require 'org))
+(require 'org)
(require 'gnus-util)
+(require 'gnus-art)
+(require 'mail-utils)
+(require 'org-agenda)
+(require 'org-capture)
(defgroup org-contacts nil
- "Options concerning contacts management."
+ "Options about contacts management."
:group 'org)
(defcustom org-contacts-files nil
"List of Org files to use as contacts source.
-If set to nil, all your Org files will be used."
+When set to nil, all your Org files will be used."
:type '(repeat file)
:group 'org-contacts)
@@ -58,6 +61,11 @@ If set to nil, all your Org files will be used."
:type 'string
:group 'org-contacts)
+(defcustom org-contacts-tel-property "PHONE"
+ "Name of the property for contact phone number."
+ :type 'string
+ :group 'org-contacts)
+
(defcustom org-contacts-address-property "ADDRESS"
"Name of the property for contact address."
:type 'string
@@ -68,8 +76,20 @@ If set to nil, all your Org files will be used."
:type 'string
:group 'org-contacts)
+(defcustom org-contacts-note-property "NOTE"
+ "Name of the property for contact note."
+ :type 'string
+ :group 'org-contacts)
+
+(defcustom org-contacts-alias-property "ALIAS"
+ "Name of the property for contact name alias."
+ :type 'string
+ :group 'org-contacts)
+
+
(defcustom org-contacts-birthday-format "Birthday: %l (%Y)"
- "Format of the anniversary agenda entry. The following replacements are available:
+ "Format of the anniversary agenda entry.
+The following replacements are available:
%h - Heading name
%l - Link to the heading
@@ -113,7 +133,13 @@ If set to nil, all your Org files will be used."
:type 'string
:group 'org-contacts)
-(defcustom org-contacts-matcher (concat org-contacts-email-property "<>\"\"")
+(defcustom org-contacts-matcher
+ (mapconcat 'identity (list org-contacts-email-property
+ org-contacts-alias-property
+ org-contacts-tel-property
+ org-contacts-address-property
+ org-contacts-birthday-property)
+ "<>\"\"|")
"Matching rule for finding heading that are contacts.
This can be a tag name, or a property check."
:type 'string
@@ -130,6 +156,24 @@ This overrides `org-email-link-description-format' if set."
:group 'org-contacts
:type 'file)
+(defcustom org-contacts-enable-completion t
+ "Enable or not the completion in `message-mode' with `org-contacts'."
+ :group 'org-contacts
+ :type 'boolean)
+
+;; Decalre external functions and variables
+(declare-function org-reverse-string "org")
+(declare-function diary-ordinal-suffix "ext:diary-lib")
+(declare-function wl-summary-message-number "ext:wl-summary")
+(declare-function wl-address-header-extract-address "ext:wl-address")
+(declare-function wl-address-header-extract-realname "ext:wl-address")
+(declare-function erc-buffer-list "ext:erc")
+(declare-function erc-get-channel-user-list "ext:erc")
+(declare-function google-maps-static-show "ext:google-maps-static")
+(declare-function elmo-message-field "ext:elmo-pipe")
+(declare-function std11-narrow-to-header "ext:std11")
+(declare-function std11-fetch-field "ext:std11")
+
(defvar org-contacts-keymap
(let ((map (make-sparse-keymap)))
(define-key map "M" 'org-contacts-view-send-email)
@@ -137,38 +181,66 @@ This overrides `org-email-link-description-format' if set."
map)
"The keymap used in `org-contacts' result list.")
+(defvar org-contacts-db nil
+ "Org Contacts database.")
+
+(defvar org-contacts-last-update nil
+ "Last time the Org Contacts database has been updated.")
+
(defun org-contacts-files ()
"Return list of Org files to use for contact management."
(or org-contacts-files (org-agenda-files t 'ifmode)))
+(defun org-contacts-db-need-update-p ()
+ "Determine whether `org-contacts-db' needs to be refreshed."
+ (or (null org-contacts-last-update)
+ (org-find-if (lambda (file)
+ (or (time-less-p org-contacts-last-update
+ (elt (file-attributes file) 5))))
+ (org-contacts-files))))
+
+(defun org-contacts-db ()
+ "Return the latest Org Contacts Database."
+ (let* (todo-only
+ (contacts-matcher
+ (cdr (org-make-tags-matcher org-contacts-matcher)))
+ markers result)
+ (when (org-contacts-db-need-update-p)
+ (message "Update Org Contacts Database")
+ (dolist (file (org-contacts-files))
+ (org-check-agenda-file file)
+ (with-current-buffer (org-get-agenda-file-buffer file)
+ (unless (eq major-mode 'org-mode)
+ (error "File %s is no in `org-mode'" file))
+ (org-scan-tags
+ '(add-to-list 'markers (set-marker (make-marker) (point)))
+ contacts-matcher
+ todo-only)))
+ (dolist (marker markers result)
+ (org-with-point-at marker
+ (add-to-list 'result
+ (list (org-get-heading t) marker (org-entry-properties marker 'all)))))
+ (setf org-contacts-db result
+ org-contacts-last-update (current-time)))
+ org-contacts-db))
+
(defun org-contacts-filter (&optional name-match tags-match)
"Search for a contact maching NAME-MATCH and TAGS-MATCH.
If both match values are nil, return all contacts."
- (let* (todo-only
- (tags-matcher
- (if tags-match
- (cdr (org-make-tags-matcher tags-match))
- t))
- (name-matcher
- (if name-match
- '(org-string-match-p name-match (org-get-heading t))
- t))
- (contacts-matcher
- (cdr (org-make-tags-matcher org-contacts-matcher)))
- markers result)
- (dolist (file (org-contacts-files))
- (org-check-agenda-file file)
- (with-current-buffer (org-get-agenda-file-buffer file)
- (unless (eq major-mode 'org-mode)
- (error "File %s is no in `org-mode'" file))
- (org-scan-tags
- '(add-to-list 'markers (set-marker (make-marker) (point)))
- `(and ,contacts-matcher ,tags-matcher ,name-matcher)
- todo-only)))
- (dolist (marker markers result)
- (org-with-point-at marker
- (add-to-list 'result
- (list (org-get-heading t) marker (org-entry-properties marker 'all)))))))
+ (if (and (null name-match)
+ (null tags-match))
+ (org-contacts-db)
+ (loop for contact in (org-contacts-db)
+ if (or
+ (and name-match
+ (org-string-match-p name-match
+ (first contact)))
+ (and tags-match
+ (org-find-if (lambda (tag)
+ (org-string-match-p tags-match tag))
+ (org-split-string
+ (or (cdr (assoc-string "ALLTAGS" (caddr contact))) "") ":"))))
+ collect contact)))
(when (not (fboundp 'completion-table-case-fold))
;; That function is new in Emacs 24...
@@ -177,67 +249,256 @@ If both match values are nil, return all contacts."
(let ((completion-ignore-case (not dont-fold)))
(complete-with-action action table string pred)))))
-(defun org-contacts-complete-name (&optional start)
+(defun org-contacts-try-completion-prefix (to-match collection &optional predicate)
+ "Custom implementation of `try-completion'.
+This version works only with list and alist and it looks at all
+prefixes rather than just the beginning of the string."
+ (loop with regexp = (concat "\\b" (regexp-quote to-match))
+ with ret = nil
+ with ret-start = nil
+ with ret-end = nil
+
+ for el in collection
+ for string = (if (listp el) (car el) el)
+
+ for start = (when (or (null predicate) (funcall predicate string))
+ (string-match regexp string))
+
+ if start
+ do (let ((end (match-end 0))
+ (len (length string)))
+ (if (= end len)
+ (return t)
+ (destructuring-bind (string start end)
+ (if (null ret)
+ (values string start end)
+ (org-contacts-common-substring
+ ret ret-start ret-end
+ string start end))
+ (setf ret string
+ ret-start start
+ ret-end end))))
+
+ finally (return
+ (replace-regexp-in-string "\\`[ \t\n]*" "" ret))))
+
+(defun org-contacts-compare-strings (s1 start1 end1 s2 start2 end2 &optional ignore-case)
+ "Compare the contents of two strings, using `compare-strings'.
+
+This function works like `compare-strings' excepted that it
+returns a cons.
+- The CAR is the number of characters that match at the beginning.
+- The CDR is T is the two strings are the same and NIL otherwise."
+ (let ((ret (compare-strings s1 start1 end1 s2 start2 end2 ignore-case)))
+ (if (eq ret t)
+ (cons (or end1 (length s1)) t)
+ (cons (1- (abs ret)) nil))))
+
+(defun org-contacts-common-substring (s1 start1 end1 s2 start2 end2)
+ "Extract the common substring between S1 and S2.
+
+This function extracts the common substring between S1 and S2 and
+adjust the part that remains common.
+
+START1 and END1 delimit the part in S1 that we know is common
+between the two strings. This applies to START2 and END2 for S2.
+
+This function returns a list whose contains:
+- The common substring found.
+- The new value of the start of the known inner substring.
+- The new value of the end of the known inner substring."
+ ;; Given two strings:
+ ;; s1: "foo bar baz"
+ ;; s2: "fooo bar baz"
+ ;; and the inner substring is "bar"
+ ;; then: start1 = 4, end1 = 6, start2 = 5, end2 = 7
+ ;;
+ ;; To find the common substring we will compare two substrings:
+ ;; " oof" and " ooof" to find the beginning of the common substring.
+ ;; " baz" and " baz" to find the end of the common substring.
+ (let* ((len1 (length s1))
+ (start1 (or start1 0))
+ (end1 (or end1 len1))
+
+ (len2 (length s2))
+ (start2 (or start2 0))
+ (end2 (or end2 len2))
+
+ (new-start (car (org-contacts-compare-strings
+ (substring (org-reverse-string s1) (- len1 start1)) nil nil
+ (substring (org-reverse-string s2) (- len2 start2)) nil nil)))
+
+ (new-end (+ end1 (car (org-contacts-compare-strings
+ (substring s1 end1) nil nil
+ (substring s2 end2) nil nil)))))
+ (list (substring s1 (- start1 new-start) new-end)
+ new-start
+ (+ new-start (- end1 start1)))))
+
+(defun org-contacts-all-completions-prefix (to-match collection &optional predicate)
+ "Custom version of `all-completions'.
+This version works only with list and alist and it looks at all
+prefixes rather than just the beginning of the string."
+ (loop with regexp = (concat "\\b" (regexp-quote to-match))
+ for el in collection
+ for string = (if (listp el) (car el) el)
+ for match? = (when (and (or (null predicate) (funcall predicate string)))
+ (string-match regexp string))
+ if match?
+ collect (progn
+ (let ((end (match-end 0)))
+ (org-no-properties string)
+ (when (< end (length string))
+ ;; Here we add a text property that will be used
+ ;; later to highlight the character right after
+ ;; the common part between each addresses.
+ ;; See `org-contacts-display-sort-function'.
+ (put-text-property end (1+ end) 'org-contacts-prefix 't string)))
+ string)))
+
+(defun org-contacts-make-collection-prefix (collection)
+ "Make a collection function from COLLECTION which will match on prefixes."
+ (lexical-let ((collection collection))
+ (lambda (string predicate flag)
+ (cond ((eq flag nil)
+ (org-contacts-try-completion-prefix string collection predicate))
+ ((eq flag t)
+ ;; `org-contacts-all-completions-prefix' has already been
+ ;; used to compute `all-completions'.
+ collection)
+ ((eq flag 'lambda)
+ (org-contacts-test-completion-prefix string collection predicate))
+ ((and (listp flag) (eq (car flag) 'boundaries))
+ (destructuring-bind (to-ignore &rest suffix)
+ flag
+ (org-contacts-boundaries-prefix string collection predicate suffix)))
+ ((eq flag 'metadata)
+ (org-contacts-metadata-prefix string collection predicate))
+ (t nil ; operation unsupported
+ )))))
+
+(defun org-contacts-display-sort-function (completions)
+ "Sort function for contacts display."
+ (mapcar (lambda (string)
+ (loop with len = (1- (length string))
+ for i upfrom 0 to len
+ if (memq 'org-contacts-prefix
+ (text-properties-at i string))
+ do (set-text-properties
+ i (1+ i)
+ (list 'font-lock-face
+ (if (char-equal (aref string i)
+ (string-to-char " "))
+ ;; Spaces can't be bold.
+ 'underline
+ 'bold)) string)
+ else
+ do (set-text-properties i (1+ i) nil string)
+ finally (return string)))
+ completions))
+
+(defun org-contacts-test-completion-prefix (string collection predicate)
+ ;; Prevents `org-find-if' from redefining `predicate' and going into
+ ;; an infinite loop.
+ (lexical-let ((predicate predicate))
+ (org-find-if (lambda (el)
+ (and (or (null predicate) (funcall predicate el))
+ (string= string el)))
+ collection)))
+
+(defun org-contacts-boundaries-prefix (string collection predicate suffix)
+ (list* 'boundaries (completion-boundaries string collection predicate suffix)))
+
+(defun org-contacts-metadata-prefix (string collection predicate)
+ '(metadata .
+ ((display-sort-function . org-contacts-display-sort-function))))
+
+(defun org-contacts-complete-group (start end string)
+ "Complete text at START from a group.
+
+A group FOO is composed of contacts with the tag FOO."
+ (let* ((completion-ignore-case org-contacts-completion-ignore-case)
+ (group-completion-p (org-string-match-p
+ (concat "^" org-contacts-group-prefix) string)))
+ (when group-completion-p
+ (let ((completion-list
+ (all-completions
+ string
+ (mapcar (lambda (group)
+ (propertize (concat org-contacts-group-prefix group)
+ 'org-contacts-group group))
+ (org-uniquify
+ (loop for contact in (org-contacts-filter)
+ nconc (org-split-string
+ (or (cdr (assoc-string "ALLTAGS" (caddr contact))) "") ":")))))))
+ (list start end
+ (if (= (length completion-list) 1)
+ ;; We've foudn the correct group, returns the address
+ (lexical-let ((tag (get-text-property 0 'org-contacts-group
+ (car completion-list))))
+ (lambda (string pred &optional to-ignore)
+ (mapconcat 'identity
+ (loop for contact in (org-contacts-filter
+ nil
+ tag)
+ ;; The contact name is always the car of the assoc-list
+ ;; returned by `org-contacts-filter'.
+ for contact-name = (car contact)
+ ;; Grab the first email of the contact
+ for email = (car (split-string
+ (or
+ (cdr (assoc-string org-contacts-email-property
+ (caddr contact)))
+ "")))
+ ;; If the user has an email address, append USER <EMAIL>.
+ if email collect (org-contacts-format-email contact-name email))
+ ", ")))
+ ;; We haven't found the correct group
+ (completion-table-case-fold completion-list
+ (not org-contacts-completion-ignore-case))))))))
+
+(defun org-contacts-complete-name (start end string)
"Complete text at START with a user name and email."
- (let* ((end (point))
- (start (or start
- (save-excursion
- (re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*")
- (goto-char (match-end 0))
- (point))))
- (orig (buffer-substring start end))
- (completion-ignore-case org-contacts-completion-ignore-case)
- (group-completion-p (org-string-match-p (concat "^" org-contacts-group-prefix) orig))
+ (let* ((completion-ignore-case org-contacts-completion-ignore-case)
(completion-list
- (if group-completion-p
- (mapcar (lambda (group) (propertize (concat org-contacts-group-prefix group) 'org-contacts-group group))
- (org-uniquify
- (loop for contact in (org-contacts-filter)
- with group-list
- nconc (org-split-string
- (or (cdr (assoc-string "ALLTAGS" (caddr contact))) "") ":"))))
- (loop for contact in (org-contacts-filter)
- ;; The contact name is always the car of the assoc-list
- ;; returned by `org-contacts-filter'.
- for contact-name = (car contact)
- ;; Build the list of the user email addresses.
- for email-list = (split-string (or
- (cdr (assoc-string org-contacts-email-property (caddr contact)))
- ""))
- ;; If the user has email addresses…
- if email-list
- ;; … append a list of USER <EMAIL>.
- nconc (loop for email in email-list
- collect (org-contacts-format-email contact-name email)))))
- (completion-list (all-completions orig completion-list)))
- ;; If we are completing a group, and that's the only group, just return
- ;; the real result.
- (when (and group-completion-p
- (= (length completion-list) 1))
- (setq completion-list
- (list (concat (car completion-list) ";: "
- (mapconcat 'identity
- (loop for contact in (org-contacts-filter
- nil
- (get-text-property 0 'org-contacts-group (car completion-list)))
- ;; The contact name is always the car of the assoc-list
- ;; returned by `org-contacts-filter'.
- for contact-name = (car contact)
- ;; Grab the first email of the contact
- for email = (car (split-string (or
- (cdr (assoc-string org-contacts-email-property (caddr contact)))
- "")))
- ;; If the user has an email address, append USER <EMAIL>.
- if email collect (org-contacts-format-email contact-name email))
- ", ")))))
- (list start end (completion-table-case-fold completion-list (not org-contacts-completion-ignore-case)))))
-
-(defun org-contacts-message-complete-function ()
+ (loop for contact in (org-contacts-filter)
+ ;; The contact name is always the car of the assoc-list
+ ;; returned by `org-contacts-filter'.
+ for contact-name = (car contact)
+ ;; Build the list of the user email addresses.
+ for email-list = (split-string (or
+ (cdr (assoc-string org-contacts-email-property
+ (caddr contact))) ""))
+ ;; If the user has email addresses…
+ if email-list
+ ;; … append a list of USER <EMAIL>.
+ nconc (loop for email in email-list
+ collect (org-contacts-format-email contact-name email))))
+ (completion-list (org-contacts-all-completions-prefix
+ string
+ (org-uniquify completion-list))))
+ (when completion-list
+ (list start end
+ (org-contacts-make-collection-prefix completion-list)))))
+
+(defun org-contacts-message-complete-function (&optional start)
"Function used in `completion-at-point-functions' in `message-mode'."
+ ;; Avoid to complete in `post-command-hook'.
+ (when completion-in-region-mode
+ (remove-hook 'post-command-hook #'completion-in-region--postch))
(let ((mail-abbrev-mode-regexp
"^\\(Resent-To\\|To\\|B?Cc\\|Reply-To\\|From\\|Mail-Followup-To\\|Mail-Copies-To\\|Disposition-Notification-To\\|Return-Receipt-To\\):"))
- (when (mail-abbrev-in-expansion-header-p)
- (org-contacts-complete-name))))
+ (when (mail-abbrev-in-expansion-header-p)
+ (lexical-let*
+ ((end (point))
+ (start (or start
+ (save-excursion
+ (re-search-backward "\\(\\`\\|[\n:,]\\)[ \t]*")
+ (goto-char (match-end 0))
+ (point))))
+ (string (buffer-substring start end)))
+ (or (org-contacts-complete-group start end string)
+ (org-contacts-complete-name start end string))))))
(defun org-contacts-gnus-get-name-email ()
"Get name and email address from Gnus message."
@@ -272,6 +533,7 @@ If both match values are nil, return all contacts."
;; show the next heading
(org-flag-heading nil)))))))
+(org-no-warnings (defvar date)) ;; unprefixed, from calendar.el
(defun org-contacts-anniversaries (&optional field format)
"Compute FIELD anniversary for each contact, returning FORMAT.
Default FIELD value is \"BIRTHDAY\".
@@ -342,6 +604,7 @@ This function should be called from `gnus-article-prepare-hook'."
(org-set-property org-contacts-last-read-mail-property link)))))))
(defun org-contacts-icon-as-string ()
+ "Return the contact icon as a string."
(let ((image (org-contacts-get-icon)))
(concat
(propertize "-" 'display
@@ -359,9 +622,9 @@ This function should be called from `gnus-article-prepare-hook'."
(let ((org-agenda-files (org-contacts-files))
(org-agenda-skip-function
(lambda () (org-agenda-skip-if nil `(notregexp ,name))))
- (org-agenda-format (propertize
- "%(org-contacts-icon-as-string)% p% s%(org-contacts-irc-number-of-unread-messages)%+T"
- 'keymap org-contacts-keymap))
+ (org-agenda-prefix-format (propertize
+ "%(org-contacts-icon-as-string)% s%(org-contacts-irc-number-of-unread-messages) "
+ 'keymap org-contacts-keymap))
(org-agenda-overriding-header
(or org-agenda-overriding-header
(concat "List of contacts matching `" name "':"))))
@@ -378,12 +641,17 @@ This function should be called from `gnus-article-prepare-hook'."
(org-completing-read
prompt (org-contacts-filter) predicate t initial-input hist def inherit-input-method))
+(defun org-contacts-format-name (name)
+ "Trim any local formatting to get a bare NAME."
+ ;; Remove radio targets characters
+ (replace-regexp-in-string org-radio-target-regexp "\\1" name))
+
(defun org-contacts-format-email (name email)
- "Format a mail address."
+ "Format an EMAIL address corresponding to NAME."
(unless email
(error "`email' cannot be nul"))
(if name
- (concat name " <" email ">")
+ (concat (org-contacts-format-name name) " <" email ">")
email))
(defun org-contacts-check-mail-address (mail)
@@ -406,7 +674,7 @@ This function should be called from `gnus-article-prepare-hook'."
"Add some hooks for Gnus user.
This adds `org-contacts-gnus-check-mail-address' and
`org-contacts-gnus-store-last-mail' to
-`gnus-article-prepare-hook'. It also adds a binding on `;' in
+`gnus-article-prepare-hook'. It also adds a binding on `;' in
`gnus-summary-mode-map' to `org-contacts-gnus-article-from-goto'"
(require 'gnus)
(require 'gnus-art)
@@ -414,7 +682,8 @@ This adds `org-contacts-gnus-check-mail-address' and
(add-hook 'gnus-article-prepare-hook 'org-contacts-gnus-check-mail-address)
(add-hook 'gnus-article-prepare-hook 'org-contacts-gnus-store-last-mail))
-(when (boundp 'completion-at-point-functions)
+(when (and org-contacts-enable-completion
+ (boundp 'completion-at-point-functions))
(add-hook 'message-mode-hook
(lambda ()
(add-to-list 'completion-at-point-functions
@@ -426,18 +695,19 @@ Works from wl-summary-mode and mime-view-mode - that is while viewing email.
Depends on Wanderlust been loaded."
(with-current-buffer (org-capture-get :original-buffer)
(cond
- ((eq major-mode 'wl-summary-mode) (when wl-summary-buffer-elmo-folder
+ ((eq major-mode 'wl-summary-mode) (when (and (boundp 'wl-summary-buffer-elmo-folder)
+ wl-summary-buffer-elmo-folder)
(elmo-message-field
wl-summary-buffer-elmo-folder
(wl-summary-message-number)
'from)))
((eq major-mode 'mime-view-mode) (std11-narrow-to-header)
- (prog1
- (std11-fetch-field "From")
- (widen))))))
+ (prog1
+ (std11-fetch-field "From")
+ (widen))))))
(defun org-contacts-wl-get-name-email ()
- "Get name and email address from wanderlust email.
+ "Get name and email address from Wanderlust email.
See `org-contacts-wl-get-from-header-content' for limitations."
(let ((from (org-contacts-wl-get-from-header-content)))
(when from
@@ -446,13 +716,14 @@ See `org-contacts-wl-get-from-header-content' for limitations."
(defun org-contacts-template-wl-name (&optional return-value)
"Try to return the contact name for a template from wl.
-If not found return RETURN-VALUE or something that would ask the user."
+If not found, return RETURN-VALUE or something that would ask the
+user."
(or (car (org-contacts-wl-get-name-email))
return-value
"%^{Name}"))
(defun org-contacts-template-wl-email (&optional return-value)
- "Try to return the contact email for a template from wl.
+ "Try to return the contact email for a template from Wanderlust.
If not found return RETURN-VALUE or something that would ask the user."
(or (cadr (org-contacts-wl-get-name-email))
return-value
@@ -460,7 +731,8 @@ If not found return RETURN-VALUE or something that would ask the user."
(defun org-contacts-view-send-email (&optional ask)
"Send email to the contact at point.
-If ASK is set, ask for the email address even if there's only one address."
+If ASK is set, ask for the email address even if there's only one
+address."
(interactive "P")
(let ((marker (org-get-at-bol 'org-hd-marker)))
(org-with-point-at marker
@@ -536,24 +808,31 @@ If ASK is set, ask for the email address even if there's only one address."
(defun erc-nicknames-list ()
"Return all nicknames of all ERC buffers."
- (if (fboundp 'erc-buffer-list)
- (loop for buffer in (erc-buffer-list)
- nconc (with-current-buffer buffer
- (loop for user-entry in (mapcar 'car (erc-get-channel-user-list))
- collect (elt user-entry 1))))))
+ (loop for buffer in (erc-buffer-list)
+ nconc (with-current-buffer buffer
+ (loop for user-entry in (mapcar 'car (erc-get-channel-user-list))
+ collect (elt user-entry 1)))))
(add-to-list 'org-property-set-functions-alist
`(,org-contacts-nickname-property . org-contacts-completing-read-nickname))
(defun org-contacts-vcard-escape (str)
- "Escape ; , and \n in STR for use in the VCard format.
-Thanks to http://www.emacswiki.org/cgi-bin/wiki/bbdb-vcard-export.el for the regexp."
+ "Escape ; , and \n in STR for the VCard format."
+ ;; Thanks to this library for the regexp:
+ ;; http://www.emacswiki.org/cgi-bin/wiki/bbdb-vcard-export.el
(when str
- (replace-regexp-in-string "\n" "\\\\n" (replace-regexp-in-string "\\(;\\|,\\|\\\\\\)" "\\\\\\1" str))))
+ (replace-regexp-in-string
+ "\n" "\\\\n"
+ (replace-regexp-in-string "\\(;\\|,\\|\\\\\\)" "\\\\\\1" str))))
(defun org-contacts-vcard-encode-name (name)
- "Try to encode NAME as VCard's N property. The N property expects FamilyName;GivenName;AdditionalNames;Prefix;Postfix.
-Org-contacts does not specify how to encode the name. So we try to do our best."
+ "Try to encode NAME as VCard's N property.
+The N property expects
+
+ FamilyName;GivenName;AdditionalNames;Prefix;Postfix.
+
+Org-contacts does not specify how to encode the name. So we try
+to do our best."
(concat (replace-regexp-in-string "\\(\\w+\\) \\(.*\\)" "\\2;\\1" name) ";;;"))
(defun org-contacts-vcard-format (contact)
@@ -561,16 +840,30 @@ Org-contacts does not specify how to encode the name. So we try to do our best."
(let* ((properties (caddr contact))
(name (org-contacts-vcard-escape (car contact)))
(n (org-contacts-vcard-encode-name name))
- (email (org-contacts-vcard-escape (cdr (assoc-string org-contacts-email-property properties))))
+ (email (cdr (assoc-string org-contacts-email-property properties)))
+ (tel (cdr (assoc-string org-contacts-tel-property properties)))
+ (note (cdr (assoc-string org-contacts-note-property properties)))
(bday (org-contacts-vcard-escape (cdr (assoc-string org-contacts-birthday-property properties))))
(addr (cdr (assoc-string org-contacts-address-property properties)))
(nick (org-contacts-vcard-escape (cdr (assoc-string org-contacts-nickname-property properties))))
-
(head (format "BEGIN:VCARD\nVERSION:3.0\nN:%s\nFN:%s\n" n name)))
(concat head
- (when email (format "EMAIL:%s\n" email))
+ (when email (progn
+ (setq emails-list (split-string email "[,;: ]+"))
+ (setq result "")
+ (while emails-list
+ (setq result (concat result "EMAIL:" (car emails-list) "\n"))
+ (setq emails-list (cdr emails-list)))
+ result))
(when addr
(format "ADR:;;%s\n" (replace-regexp-in-string "\\, ?" ";" addr)))
+ (when tel (progn
+ (setq phones-list (split-string tel "[,;: ]+"))
+ (setq result "")
+ (while phones-list
+ (setq result (concat result "TEL:" (car phones-list) "\n"))
+ (setq phones-list (cdr phones-list)))
+ result))
(when bday
(let ((cal-bday (calendar-gregorian-from-absolute (org-time-string-to-absolute bday))))
(format "BDAY:%04d-%02d-%02d\n"
@@ -578,44 +871,47 @@ Org-contacts does not specify how to encode the name. So we try to do our best."
(calendar-extract-month cal-bday)
(calendar-extract-day cal-bday))))
(when nick (format "NICKNAME:%s\n" nick))
+ (when note (format "NOTE:%s\n" note))
"END:VCARD\n\n")))
(defun org-contacts-export-as-vcard (&optional name file to-buffer)
- "Export all contacts matching NAME as VCard 3.0. It TO-BUFFER is nil, the content is written to FILE or `org-contacts-vcard-file'. If TO-BUFFER is non-nil, the buffer is created and the VCard is written into that buffer."
+ "Export all contacts matching NAME as VCard 3.0.
+If TO-BUFFER is nil, the content is written to FILE or
+`org-contacts-vcard-file'. If TO-BUFFER is non-nil, the buffer
+is created and the VCard is written into that buffer."
(interactive) ; TODO ask for name?
(let* ((filename (or file org-contacts-vcard-file))
(buffer (if to-buffer
(get-buffer-create to-buffer)
- (find-file-noselect filename))))
-
+ (find-file-noselect filename))))
(message "Exporting...")
-
(set-buffer buffer)
(let ((inhibit-read-only t)) (erase-buffer))
(fundamental-mode)
- (org-install-letbind)
-
(when (fboundp 'set-buffer-file-coding-system)
(set-buffer-file-coding-system coding-system-for-write))
-
(loop for contact in (org-contacts-filter name)
- do (insert (org-contacts-vcard-format contact)))
-
+ do (insert (org-contacts-vcard-format contact)))
(if to-buffer
(current-buffer)
- (progn (save-buffer) (kill-buffer)))))
+ (progn (save-buffer) (kill-buffer)))))
(defun org-contacts-show-map (&optional name)
- "Show contacts on a map. Requires google-maps-el."
+ "Show contacts on a map.
+Requires google-maps-el."
(interactive)
(unless (fboundp 'google-maps-static-show)
(error "`org-contacts-show-map' requires `google-maps-el'"))
(google-maps-static-show
:markers
(loop
- for contact in (org-contacts-filter name)
- for addr = (cdr (assoc-string org-contacts-address-property (caddr contact)))
- if addr
- collect (cons (list addr) (list :label (string-to-char (car contact)))))))
+ for contact in (org-contacts-filter name)
+ for addr = (cdr (assoc-string org-contacts-address-property (caddr contact)))
+ if addr
+ collect (cons (list addr) (list :label (string-to-char (car contact)))))))
+
+(provide 'org-contacts)
(provide 'org-contacts)
+
+;;; org-contacts.el ends here
diff --git a/contrib/lisp/org-contribdir.el b/contrib/lisp/org-contribdir.el
index 37b06a4..8132750 100644
--- a/contrib/lisp/org-contribdir.el
+++ b/contrib/lisp/org-contribdir.el
@@ -1,5 +1,5 @@
;;; org-contribdir.el --- Mark the location of the contrib directory
-;; Copyright (C) 2009-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2009-2013 Free Software Foundation, Inc.
;;
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -8,12 +8,12 @@
;;
;; This file is not yet part of GNU Emacs.
;;
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
diff --git a/contrib/lisp/org-depend.el b/contrib/lisp/org-depend.el
index d741dbe..dc99a1d 100644
--- a/contrib/lisp/org-depend.el
+++ b/contrib/lisp/org-depend.el
@@ -1,5 +1,5 @@
;;; org-depend.el --- TODO dependencies for Org-mode
-;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
;;
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -13,15 +13,13 @@
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
@@ -205,13 +203,15 @@ This does two different kinds of triggers:
property is seen as an entry id. Org-mode finds the entry with the
corresponding ID property and switches it to the state TODO as well."
+ ;; Refresh the effort text properties
+ (org-refresh-properties org-effort-property 'org-effort)
;; Get information from the plist
(let* ((type (plist-get change-plist :type))
(pos (plist-get change-plist :position))
(from (plist-get change-plist :from))
(to (plist-get change-plist :to))
(org-log-done nil) ; IMPROTANT!: no logging during automatic trigger!
- trigger triggers tr p1 kwd)
+ trigger triggers tr p1 kwd id)
(catch 'return
(unless (eq type 'todo-state-change)
;; We are only handling todo-state-change....
@@ -268,7 +268,7 @@ This does two different kinds of triggers:
(tags (match-string 5))
(priority (org-get-priority (or (match-string 3) "")))
(effort (when (or effort-up effort-down)
- (let ((effort (org-get-effort)))
+ (let ((effort (get-text-property (point) 'org-effort)))
(when effort
(org-duration-string-to-minutes effort))))))
(push (list (point) todo-kwd priority tags effort)
@@ -311,15 +311,15 @@ This does two different kinds of triggers:
(cond (priority-up
(or p1-gt
(and (equal p1 p2)
- (or (and effort-up e1-gt)
- (and effort-down e1-lt)))))
+ (or (and effort-up e1-lt)
+ (and effort-down e2-gt)))))
(priority-down
(or p1-lt
(and (equal p1 p2)
- (or (and effort-up e1-gt)
- (and effort-down e1-lt)))))
+ (or (and effort-up e1-lt)
+ (and effort-down e2-gt)))))
(effort-up
- (or e1-gt (and (equal e1 e2) p1-gt)))
+ (or e2-gt (and (equal e1 e2) p1-gt)))
(effort-down
(or e1-lt (and (equal e1 e2) p1-gt))))))))
(when items
diff --git a/contrib/lisp/org-drill.el b/contrib/lisp/org-drill.el
index 2ffc201..5bf6dd4 100644
--- a/contrib/lisp/org-drill.el
+++ b/contrib/lisp/org-drill.el
@@ -1,28 +1,42 @@
-;;; -*- coding: utf-8-unix -*-
+;; -*- coding: utf-8-unix -*-
;;; org-drill.el - Self-testing using spaced repetition
;;;
-;;; Author: Paul Sexton <eeeickythump@gmail.com>
-;;; Version: 2.3.6
-;;; Repository at http://bitbucket.org/eeeickythump/org-drill/
+;; Author: Paul Sexton <eeeickythump@gmail.com>
+;; Version: 2.3.7
+;; Repository at http://bitbucket.org/eeeickythump/org-drill/
+;;
+;; This file is not part of GNU Emacs.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary and synopsis:
;;;
-;;;
-;;; Synopsis
-;;; ========
-;;;
-;;; Uses the SuperMemo spaced repetition algorithms to conduct interactive
-;;; "drill sessions", where the material to be remembered is presented to the
-;;; student in random order. The student rates his or her recall of each item,
-;;; and this information is used to schedule the item for later revision.
-;;;
-;;; Each drill session can be restricted to topics in the current buffer
-;;; (default), one or several files, all agenda files, or a subtree. A single
-;;; topic can also be drilled.
-;;;
-;;; Different "card types" can be defined, which present their information to
-;;; the student in different ways.
-;;;
-;;; See the file README.org for more detailed documentation.
-
+;; Uses the SuperMemo spaced repetition algorithms to conduct interactive
+;; "drill sessions", where the material to be remembered is presented to the
+;; student in random order. The student rates his or her recall of each item,
+;; and this information is used to schedule the item for later revision.
+;;
+;; Each drill session can be restricted to topics in the current buffer
+;; (default), one or several files, all agenda files, or a subtree. A single
+;; topic can also be drilled.
+;;
+;; Different "card types" can be defined, which present their information to
+;; the student in different ways.
+;;
+;; See the file README.org for more detailed documentation.
+;;
+;;; Code:
(eval-when-compile (require 'cl))
(eval-when-compile (require 'hi-lock))
@@ -30,41 +44,30 @@
(require 'org-id)
(require 'org-learn)
-
(defgroup org-drill nil
"Options concerning interactive drill sessions in Org mode (org-drill)."
:tag "Org-Drill"
:group 'org-link)
-
-
-(defcustom org-drill-question-tag
- "drill"
+(defcustom org-drill-question-tag "drill"
"Tag which topics must possess in order to be identified as review topics
by `org-drill'."
:group 'org-drill
:type 'string)
-
-(defcustom org-drill-maximum-items-per-session
- 30
+(defcustom org-drill-maximum-items-per-session 30
"Each drill session will present at most this many topics for review.
Nil means unlimited."
:group 'org-drill
:type '(choice integer (const nil)))
-
-
-(defcustom org-drill-maximum-duration
- 20
+(defcustom org-drill-maximum-duration 20
"Maximum duration of a drill session, in minutes.
Nil means unlimited."
:group 'org-drill
:type '(choice integer (const nil)))
-
-(defcustom org-drill-failure-quality
- 2
+(defcustom org-drill-failure-quality 2
"If the quality of recall for an item is this number or lower,
it is regarded as an unambiguous failure, and the repetition
interval for the card is reset to 0 days. If the quality is higher
@@ -78,9 +81,7 @@ really sensible."
:group 'org-drill
:type '(choice (const 2) (const 1)))
-
-(defcustom org-drill-forgetting-index
- 10
+(defcustom org-drill-forgetting-index 10
"What percentage of items do you consider it is 'acceptable' to
forget each drill session? The default is 10%. A warning message
is displayed at the end of the session if the percentage forgotten
@@ -88,17 +89,13 @@ climbs above this number."
:group 'org-drill
:type 'integer)
-
-(defcustom org-drill-leech-failure-threshold
- 15
+(defcustom org-drill-leech-failure-threshold 15
"If an item is forgotten more than this many times, it is tagged
as a 'leech' item."
:group 'org-drill
:type '(choice integer (const nil)))
-
-(defcustom org-drill-leech-method
- 'skip
+(defcustom org-drill-leech-method 'skip
"How should 'leech items' be handled during drill sessions?
Possible values:
- nil :: Leech items are treated the same as normal items.
@@ -109,71 +106,58 @@ Possible values:
:group 'org-drill
:type '(choice (const 'warn) (const 'skip) (const nil)))
-
(defface org-drill-visible-cloze-face
'((t (:foreground "darkseagreen")))
"The face used to hide the contents of cloze phrases."
:group 'org-drill)
-
(defface org-drill-visible-cloze-hint-face
'((t (:foreground "dark slate blue")))
"The face used to hide the contents of cloze phrases."
:group 'org-drill)
-
(defface org-drill-hidden-cloze-face
'((t (:foreground "deep sky blue" :background "blue")))
"The face used to hide the contents of cloze phrases."
:group 'org-drill)
-
-(defcustom org-drill-use-visible-cloze-face-p
- nil
+(defcustom org-drill-use-visible-cloze-face-p nil
"Use a special face to highlight cloze-deleted text in org mode
buffers?"
:group 'org-drill
:type 'boolean)
-
-(defcustom org-drill-hide-item-headings-p
- nil
+(defcustom org-drill-hide-item-headings-p nil
"Conceal the contents of the main heading of each item during drill
sessions? You may want to enable this behaviour if item headings or tags
contain information that could 'give away' the answer."
:group 'org-drill
:type 'boolean)
-
-(defcustom org-drill-new-count-color
- "royal blue"
+(defcustom org-drill-new-count-color "royal blue"
"Foreground colour used to display the count of remaining new items
during a drill session."
:group 'org-drill
:type 'color)
-(defcustom org-drill-mature-count-color
- "green"
+(defcustom org-drill-mature-count-color "green"
"Foreground colour used to display the count of remaining mature items
during a drill session. Mature items are due for review, but are not new."
:group 'org-drill
:type 'color)
-(defcustom org-drill-failed-count-color
- "red"
+(defcustom org-drill-failed-count-color "red"
"Foreground colour used to display the count of remaining failed items
during a drill session."
:group 'org-drill
:type 'color)
-(defcustom org-drill-done-count-color
- "sienna"
+(defcustom org-drill-done-count-color "sienna"
"Foreground colour used to display the count of reviewed items
during a drill session."
:group 'org-drill
:type 'color)
-
(setplist 'org-drill-cloze-overlay-defaults
'(display "[...]"
face org-drill-hidden-cloze-face
@@ -187,60 +171,70 @@ during a drill session."
face default
window t))
+(defvar org-drill-hint-separator "||"
+ "String which, if it occurs within a cloze expression, signifies that the
+rest of the expression after the string is a `hint', to be displayed instead of
+the hidden cloze during a test.")
(defvar org-drill-cloze-regexp
- ;; ver 1 "[^][]\\(\\[[^][][^]]*\\]\\)"
- ;; ver 2 "\\(\\[.*?\\]\\|^[^[[:cntrl:]]*?\\]\\|\\[.*?$\\)"
- ;; ver 3! "\\(\\[.*?\\]\\|\\[.*?[[:cntrl:]]+.*?\\]\\)"
- "\\(\\[[[:cntrl:][:graph:][:space:]]*?\\)\\(\\||.+?\\)\\(\\]\\)")
-
+ (concat "\\(\\[[[:cntrl:][:graph:][:space:]]+?\\)\\(\\|"
+ (regexp-quote org-drill-hint-separator)
+ ".+?\\)\\(\\]\\)"))
(defvar org-drill-cloze-keywords
`((,org-drill-cloze-regexp
(1 'org-drill-visible-cloze-face nil)
(2 'org-drill-visible-cloze-hint-face t)
- (3 'org-drill-visible-cloze-face nil)
- )))
-
+ (3 'org-drill-visible-cloze-face nil))))
(defcustom org-drill-card-type-alist
- '((nil . org-drill-present-simple-card)
- ("simple" . org-drill-present-simple-card)
- ("twosided" . org-drill-present-two-sided-card)
- ("multisided" . org-drill-present-multi-sided-card)
- ("hide1cloze" . org-drill-present-multicloze-hide1)
- ("hide2cloze" . org-drill-present-multicloze-hide2)
- ("show1cloze" . org-drill-present-multicloze-show1)
- ("show2cloze" . org-drill-present-multicloze-show2)
- ("multicloze" . org-drill-present-multicloze-hide1)
- ("hidefirst" . org-drill-present-multicloze-hide-first)
- ("hidelast" . org-drill-present-multicloze-hide-last)
- ("hide1_firstmore" . org-drill-present-multicloze-hide1-firstmore)
- ("show1_lastmore" . org-drill-present-multicloze-show1-lastmore)
- ("show1_firstless" . org-drill-present-multicloze-show1-firstless)
- ("conjugate" org-drill-present-verb-conjugation
+ '((nil org-drill-present-simple-card)
+ ("simple" org-drill-present-simple-card)
+ ("twosided" org-drill-present-two-sided-card nil t)
+ ("multisided" org-drill-present-multi-sided-card nil t)
+ ("hide1cloze" org-drill-present-multicloze-hide1)
+ ("hide2cloze" org-drill-present-multicloze-hide2)
+ ("show1cloze" org-drill-present-multicloze-show1)
+ ("show2cloze" org-drill-present-multicloze-show2)
+ ("multicloze" org-drill-present-multicloze-hide1)
+ ("hidefirst" org-drill-present-multicloze-hide-first)
+ ("hidelast" org-drill-present-multicloze-hide-last)
+ ("hide1_firstmore" org-drill-present-multicloze-hide1-firstmore)
+ ("show1_lastmore" org-drill-present-multicloze-show1-lastmore)
+ ("show1_firstless" org-drill-present-multicloze-show1-firstless)
+ ("conjugate"
+ org-drill-present-verb-conjugation
org-drill-show-answer-verb-conjugation)
- ("spanish_verb" . org-drill-present-spanish-verb)
- ("translate_number" org-drill-present-translate-number
- org-drill-show-answer-translate-number))
- "Alist associating card types with presentation functions. Each entry in the
-alist takes one of two forms:
-1. (CARDTYPE . QUESTION-FN), where CARDTYPE is a string or nil (for default),
- and QUESTION-FN is a function which takes no arguments and returns a boolean
- value.
-2. (CARDTYPE QUESTION-FN ANSWER-FN), where ANSWER-FN is a function that takes
- one argument -- the argument is a function that itself takes no arguments.
- ANSWER-FN is called with the point on the active item's
- heading, just prior to displaying the item's 'answer'. It can therefore be
- used to modify the appearance of the answer. ANSWER-FN must call its argument
- before returning. (Its argument is a function that prompts the user and
- performs rescheduling)."
+ ("decline_noun"
+ org-drill-present-noun-declension
+ org-drill-show-answer-noun-declension)
+ ("spanish_verb" org-drill-present-spanish-verb)
+ ("translate_number" org-drill-present-translate-number))
+ "Alist associating card types with presentation functions. Each
+entry in the alist takes the form:
+
+;;; (CARDTYPE QUESTION-FN [ANSWER-FN DRILL-EMPTY-P])
+
+Where CARDTYPE is a string or nil (for default), and QUESTION-FN
+is a function which takes no arguments and returns a boolean
+value.
+
+When supplied, ANSWER-FN is a function that takes one argument --
+that argument is a function of no arguments, which when called,
+prompts the user to rate their recall and performs rescheduling
+of the drill item. ANSWER-FN is called with the point on the
+active item's heading, just prior to displaying the item's
+'answer'. It can therefore be used to modify the appearance of
+the answer. ANSWER-FN must call its argument before returning.
+
+When supplied, DRILL-EMPTY-P is a boolean value, default nil.
+When non-nil, cards of this type will be presented during tests
+even if their bodies are empty."
:group 'org-drill
- :type '(alist :key-type (choice string (const nil)) :value-type function))
-
+ :type '(alist :key-type (choice string (const nil))
+ :value-type function))
-(defcustom org-drill-scope
- 'file
+(defcustom org-drill-scope 'file
"The scope in which to search for drill items when conducting a
drill session. This can be any of:
@@ -267,17 +261,13 @@ directory All files with the extension '.org' in the same
(const 'agenda-with-archives) (const 'directory)
list))
-
-(defcustom org-drill-save-buffers-after-drill-sessions-p
- t
+(defcustom org-drill-save-buffers-after-drill-sessions-p t
"If non-nil, prompt to save all modified buffers after a drill session
finishes."
:group 'org-drill
:type 'boolean)
-
-(defcustom org-drill-spaced-repetition-algorithm
- 'sm5
+(defcustom org-drill-spaced-repetition-algorithm 'sm5
"Which SuperMemo spaced repetition algorithm to use for scheduling items.
Available choices are:
- SM2 :: the SM2 algorithm, used in SuperMemo 2.0
@@ -292,9 +282,7 @@ Available choices are:
:group 'org-drill
:type '(choice (const 'sm2) (const 'sm5) (const 'simple8)))
-
-(defcustom org-drill-optimal-factor-matrix
- nil
+(defcustom org-drill-optimal-factor-matrix nil
"DO NOT CHANGE THE VALUE OF THIS VARIABLE.
Persistent matrix of optimal factors, used by the SuperMemo SM5 algorithm.
@@ -306,18 +294,14 @@ pace of learning."
:group 'org-drill
:type 'sexp)
-
-(defcustom org-drill-sm5-initial-interval
- 4.0
+(defcustom org-drill-sm5-initial-interval 4.0
"In the SM5 algorithm, the initial interval after the first
successful presentation of an item is always 4 days. If you wish to change
this, you can do so here."
:group 'org-drill
:type 'float)
-
-(defcustom org-drill-add-random-noise-to-intervals-p
- nil
+(defcustom org-drill-add-random-noise-to-intervals-p nil
"If true, the number of days until an item's next repetition
will vary slightly from the interval calculated by the SM2
algorithm. The variation is very small when the interval is
@@ -325,9 +309,7 @@ small, but scales up with the interval."
:group 'org-drill
:type 'boolean)
-
-(defcustom org-drill-adjust-intervals-for-early-and-late-repetitions-p
- nil
+(defcustom org-drill-adjust-intervals-for-early-and-late-repetitions-p nil
"If true, when the student successfully reviews an item 1 or more days
before or after the scheduled review date, this will affect that date of
the item's next scheduled review, according to the algorithm presented at
@@ -342,9 +324,7 @@ is used."
:group 'org-drill
:type 'boolean)
-
-(defcustom org-drill-cloze-text-weight
- 4
+(defcustom org-drill-cloze-text-weight 4
"For card types 'hide1_firstmore', 'show1_lastmore' and 'show1_firstless',
this number determines how often the 'less favoured' situation
should arise. It will occur 1 in every N trials, where N is the
@@ -363,15 +343,12 @@ all weighted card types are treated as their unweighted equivalents."
:group 'org-drill
:type '(choice integer (const nil)))
-
-(defcustom org-drill-cram-hours
- 12
+(defcustom org-drill-cram-hours 12
"When in cram mode, items are considered due for review if
they were reviewed at least this many hours ago."
:group 'org-drill
:type 'integer)
-
;;; NEW items have never been presented in a drill session before.
;;; MATURE items HAVE been presented at least once before.
;;; - YOUNG mature items were scheduled no more than
@@ -384,17 +361,13 @@ they were reviewed at least this many hours ago."
;;; LAST-INTERVAL * (ORG-DRILL-OVERDUE-INTERVAL-FACTOR - 1) days,
;;; regardless of young/old status.
-
-(defcustom org-drill-days-before-old
- 10
+(defcustom org-drill-days-before-old 10
"When an item's inter-repetition interval rises above this value in days,
it is no longer considered a 'young' (recently learned) item."
:group 'org-drill
:type 'integer)
-
-(defcustom org-drill-overdue-interval-factor
- 1.2
+(defcustom org-drill-overdue-interval-factor 1.2
"An item is considered overdue if its scheduled review date is
more than (ORG-DRILL-OVERDUE-INTERVAL-FACTOR - 1) * LAST-INTERVAL
days in the past. For example, a value of 1.2 means an additional
@@ -406,9 +379,7 @@ should never be less than 1.0."
:group 'org-drill
:type 'float)
-
-(defcustom org-drill-learn-fraction
- 0.5
+(defcustom org-drill-learn-fraction 0.5
"Fraction between 0 and 1 that governs how quickly the spaces
between successive repetitions increase, for all items. The
default value is 0.5. Higher values make spaces increase more
@@ -418,6 +389,15 @@ exponential effect on inter-repetition spacing."
:group 'org-drill
:type 'float)
+(defvar drill-answer nil
+ "Global variable that can be bound to a correct answer when an
+item is being presented. If this variable is non-nil, the default
+presentation function will show its value instead of the default
+behaviour of revealing the contents of the drilled item.
+
+This variable is useful for card types that compute their answers
+-- for example, a card type that asks the student to translate a
+random number to another language. ")
(defvar *org-drill-session-qualities* nil)
(defvar *org-drill-start-time* 0)
@@ -448,10 +428,8 @@ for review unless they were already reviewed in the recent past?")
"DRILL_TOTAL_REPEATS" "DRILL_FAILURE_COUNT" "DRILL_AVERAGE_QUALITY"
"DRILL_EASE" "DRILL_LAST_QUALITY" "DRILL_LAST_REVIEWED"))
-
;;; Make the above settings safe as file-local variables.
-
(put 'org-drill-question-tag 'safe-local-variable 'stringp)
(put 'org-drill-maximum-items-per-session 'safe-local-variable
'(lambda (val) (or (integerp val) (null val))))
@@ -480,14 +458,11 @@ for review unless they were already reviewed in the recent past?")
(put 'org-drill-cloze-text-weight 'safe-local-variable
'(lambda (val) (or (null val) (integerp val))))
-
;;;; Utilities ================================================================
-
(defun free-marker (m)
(set-marker m nil))
-
(defmacro pop-random (place)
(let ((idx (gensym)))
`(if (null ,place)
@@ -497,13 +472,11 @@ for review unless they were already reviewed in the recent past?")
(setq ,place (append (subseq ,place 0 ,idx)
(subseq ,place (1+ ,idx)))))))))
-
(defmacro push-end (val place)
"Add VAL to the end of the sequence stored in PLACE. Return the new
value."
`(setq ,place (append ,place (list ,val))))
-
(defun shuffle-list (list)
"Randomly permute the elements of LIST (all permutations equally likely)."
;; Adapted from 'shuffle-vector' in cookie1.el
@@ -519,27 +492,23 @@ value."
(setq i (1+ i))))
list)
-
(defun round-float (floatnum fix)
"Round the floating point number FLOATNUM to FIX decimal places.
Example: (round-float 3.56755765 3) -> 3.568"
(let ((n (expt 10 fix)))
(/ (float (round (* floatnum n))) n)))
-
(defun command-keybinding-to-string (cmd)
"Return a human-readable description of the key/keys to which the command
CMD is bound, or nil if it is not bound to a key."
(let ((key (where-is-internal cmd overriding-local-map t)))
(if key (key-description key))))
-
(defun time-to-inactive-org-timestamp (time)
(format-time-string
(concat "[" (substring (cdr org-time-stamp-formats) 1 -1) "]")
time))
-
(defun org-map-drill-entries (func &optional scope &rest skip)
"Like `org-map-entries', but only drill entries are processed."
(let ((org-drill-scope (or scope org-drill-scope)))
@@ -554,7 +523,6 @@ CMD is bound, or nil if it is not bound to a key."
(t org-drill-scope))
skip)))
-
(defmacro with-hidden-cloze-text (&rest body)
`(progn
(org-drill-hide-clozed-text)
@@ -563,7 +531,6 @@ CMD is bound, or nil if it is not bound to a key."
,@body)
(org-drill-unhide-clozed-text))))
-
(defmacro with-hidden-cloze-hints (&rest body)
`(progn
(org-drill-hide-cloze-hints)
@@ -572,7 +539,6 @@ CMD is bound, or nil if it is not bound to a key."
,@body)
(org-drill-unhide-text))))
-
(defmacro with-hidden-comments (&rest body)
`(progn
(if org-drill-hide-item-headings-p
@@ -583,7 +549,6 @@ CMD is bound, or nil if it is not bound to a key."
,@body)
(org-drill-unhide-text))))
-
(defun org-drill-days-since-last-review ()
"Nil means a last review date has not yet been stored for
the item.
@@ -597,7 +562,6 @@ this should never happen."
(time-to-days (apply 'encode-time
(org-parse-time-string datestr)))))))
-
(defun org-drill-hours-since-last-review ()
"Like `org-drill-days-since-last-review', but return value is
in hours rather than days."
@@ -609,7 +573,6 @@ in hours rather than days."
(org-parse-time-string datestr))))
(* 60 60))))))
-
(defun org-drill-entry-p (&optional marker)
"Is MARKER, or the point, in a 'drill item'? This will return nil if
the point is inside a subheading of a drill item -- to handle that
@@ -619,12 +582,10 @@ situation use `org-part-of-drill-entry-p'."
(org-drill-goto-entry marker))
(member org-drill-question-tag (org-get-local-tags))))
-
(defun org-drill-goto-entry (marker)
(switch-to-buffer (marker-buffer marker))
(goto-char marker))
-
(defun org-part-of-drill-entry-p ()
"Is the current entry either the main heading of a 'drill item',
or a subheading within a drill item?"
@@ -632,7 +593,6 @@ or a subheading within a drill item?"
;; Does this heading INHERIT the drill tag
(member org-drill-question-tag (org-get-tags-at))))
-
(defun org-drill-goto-drill-entry-heading ()
"Move the point to the heading which holds the :drill: tag for this
drill entry."
@@ -644,14 +604,11 @@ drill entry."
(unless (org-up-heading-safe)
(error "Cannot find a parent heading that is marked as a drill entry"))))
-
-
(defun org-drill-entry-leech-p ()
"Is the current entry a 'leech item'?"
(and (org-drill-entry-p)
(member "leech" (org-get-local-tags))))
-
;; (defun org-drill-entry-due-p ()
;; (cond
;; (*org-drill-cram-mode*
@@ -669,7 +626,6 @@ drill entry."
;; (- (time-to-days (current-time))
;; (time-to-days item-time))))))))))
-
(defun org-drill-entry-days-overdue ()
"Returns:
- NIL if the item is not to be regarded as scheduled for review at all.
@@ -699,7 +655,6 @@ drill entry."
(- (time-to-days (current-time))
(time-to-days item-time))))))))
-
(defun org-drill-entry-overdue-p (&optional days-overdue last-interval)
"Returns true if entry that is scheduled DAYS-OVERDUE dasy in the past,
and whose last inter-repetition interval was LAST-INTERVAL, should be
@@ -715,34 +670,28 @@ from the entry at point."
(> (/ (+ days-overdue last-interval 1.0) last-interval)
org-drill-overdue-interval-factor)))
-
-
(defun org-drill-entry-due-p ()
(let ((due (org-drill-entry-days-overdue)))
(and (not (null due))
(not (minusp due)))))
-
(defun org-drill-entry-new-p ()
(and (org-drill-entry-p)
(let ((item-time (org-get-scheduled-time (point))))
(null item-time))))
-
(defun org-drill-entry-last-quality (&optional default)
(let ((quality (org-entry-get (point) "DRILL_LAST_QUALITY")))
(if quality
(string-to-number quality)
default)))
-
(defun org-drill-entry-failure-count ()
(let ((quality (org-entry-get (point) "DRILL_FAILURE_COUNT")))
(if quality
(string-to-number quality)
0)))
-
(defun org-drill-entry-average-quality (&optional default)
(let ((val (org-entry-get (point) "DRILL_AVERAGE_QUALITY")))
(if val
@@ -773,7 +722,6 @@ from the entry at point."
(string-to-number val)
default)))
-
;;; From http://www.supermemo.com/english/ol/sm5.htm
(defun org-drill-random-dispersal-factor ()
"Returns a random number between 0.5 and 1.5."
@@ -796,10 +744,9 @@ from the entry at point."
(- variation)
mean))
-
(defun org-drill-early-interval-factor (optimal-factor
- optimal-interval
- days-ahead)
+ optimal-interval
+ days-ahead)
"Arguments:
- OPTIMAL-FACTOR: interval-factor if the item had been tested
exactly when it was supposed to be.
@@ -816,7 +763,6 @@ in the matrix."
(- optimal-factor
(* delta-ofmax (/ days-ahead (+ days-ahead (* 0.6 optimal-interval)))))))
-
(defun org-drill-get-item-data ()
"Returns a list of 6 items, containing all the stored recall
data for the item at point:
@@ -854,7 +800,6 @@ in the matrix."
(t ; virgin item
(list 0 0 0 0 nil nil)))))
-
(defun org-drill-store-item-data (last-interval repeats failures
total-repeats meanq
ease)
@@ -870,11 +815,8 @@ in the matrix."
(org-set-property "DRILL_EASE"
(number-to-string (round-float ease 3))))
-
-
;;; SM2 Algorithm =============================================================
-
(defun determine-next-interval-sm2 (last-interval n ef quality
failures meanq total-repeats)
"Arguments:
@@ -923,8 +865,6 @@ Returns a list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX), wher
;;; SM5 Algorithm =============================================================
-
-
(defun initial-optimal-factor-sm5 (n ef)
(if (= 1 n)
org-drill-sm5-initial-interval
@@ -937,7 +877,6 @@ Returns a list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX), wher
(and ef-of (cdr ef-of))))
(initial-optimal-factor-sm5 n ef))))
-
(defun inter-repetition-interval-sm5 (last-interval n ef &optional of-matrix)
(let ((of (get-optimal-factor-sm5 n ef (or of-matrix
org-drill-optimal-factor-matrix))))
@@ -945,7 +884,6 @@ Returns a list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX), wher
of
(* of last-interval))))
-
(defun determine-next-interval-sm5 (last-interval n ef quality
failures meanq total-repeats
of-matrix &optional delta-days)
@@ -956,12 +894,10 @@ Returns a list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX), wher
(unless of-matrix
(setq of-matrix org-drill-optimal-factor-matrix))
(setq of-matrix (cl-copy-tree of-matrix))
-
(setq meanq (if meanq
(/ (+ quality (* meanq total-repeats 1.0))
(1+ total-repeats))
quality))
-
(let ((next-ef (modify-e-factor ef quality))
(old-ef ef)
(new-of (modify-of (get-optimal-factor-sm5 n ef of-matrix)
@@ -974,13 +910,10 @@ Returns a list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX), wher
(inter-repetition-interval-sm5
last-interval n ef of-matrix)
delta-days)))
-
(setq of-matrix
(set-optimal-factor n next-ef of-matrix
(round-float new-of 3))) ; round OF to 3 d.p.
-
(setq ef next-ef)
-
(cond
;; "Failed" -- reset repetitions to 0,
((<= quality org-drill-failure-quality)
@@ -1005,10 +938,8 @@ Returns a list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX), wher
(1+ total-repeats)
of-matrix)))))
-
;;; Simple8 Algorithm =========================================================
-
(defun org-drill-simple8-first-interval (failures)
"Arguments:
- FAILURES: integer >= 0. The total number of times the item has
@@ -1018,7 +949,6 @@ Returns the optimal FIRST interval for an item which has previously been
forgotten on FAILURES occasions."
(* 2.4849 (exp (* -0.057 failures))))
-
(defun org-drill-simple8-interval-factor (ease repetition)
"Arguments:
- EASE: floating point number >= 1.2. Corresponds to `AF' in SM8 algorithm.
@@ -1029,7 +959,6 @@ The factor by which the last interval should be
multiplied to give the next interval. Corresponds to `RF' or `OF'."
(+ 1.2 (* (- ease 1.2) (expt org-drill-learn-fraction (log repetition 2)))))
-
(defun org-drill-simple8-quality->ease (quality)
"Returns the ease (`AF' in the SM8 algorithm) which corresponds
to a mean item quality of QUALITY."
@@ -1039,7 +968,6 @@ to a mean item quality of QUALITY."
(* -1.2403 quality)
1.4515))
-
(defun determine-next-interval-simple8 (last-interval repeats quality
failures meanq totaln
&optional delta-days)
@@ -1106,11 +1034,7 @@ See the documentation for `org-drill-get-item-data' for a description of these."
(org-drill-simple8-quality->ease meanq)
failures
meanq
- totaln
- )))
-
-
-
+ totaln)))
;;; Essentially copied from `org-learn.el', but modified to
;;; optionally call the SM2 or simple8 functions.
@@ -1261,35 +1185,35 @@ How well did you do? (0-5, ?=help, e=edit, t=tags, q=quit)"
((and (>= ch ?0) (<= ch ?5))
(let ((quality (- ch ?0))
(failures (org-drill-entry-failure-count)))
- (save-excursion
- (org-drill-smart-reschedule quality
- (nth quality next-review-dates)))
- (push quality *org-drill-session-qualities*)
- (cond
- ((<= quality org-drill-failure-quality)
- (when org-drill-leech-failure-threshold
- ;;(setq failures (if failures (string-to-number failures) 0))
- ;; (org-set-property "DRILL_FAILURE_COUNT"
- ;; (format "%d" (1+ failures)))
- (if (> (1+ failures) org-drill-leech-failure-threshold)
- (org-toggle-tag "leech" 'on))))
- (t
- (let ((scheduled-time (org-get-scheduled-time (point))))
- (when scheduled-time
- (message "Next review in %d days"
- (- (time-to-days scheduled-time)
- (time-to-days (current-time))))
- (sit-for 0.5)))))
- (org-set-property "DRILL_LAST_QUALITY" (format "%d" quality))
- (org-set-property "DRILL_LAST_REVIEWED"
- (time-to-inactive-org-timestamp (current-time)))
+ (unless *org-drill-cram-mode*
+ (save-excursion
+ (org-drill-smart-reschedule quality
+ (nth quality next-review-dates)))
+ (push quality *org-drill-session-qualities*)
+ (cond
+ ((<= quality org-drill-failure-quality)
+ (when org-drill-leech-failure-threshold
+ ;;(setq failures (if failures (string-to-number failures) 0))
+ ;; (org-set-property "DRILL_FAILURE_COUNT"
+ ;; (format "%d" (1+ failures)))
+ (if (> (1+ failures) org-drill-leech-failure-threshold)
+ (org-toggle-tag "leech" 'on))))
+ (t
+ (let ((scheduled-time (org-get-scheduled-time (point))))
+ (when scheduled-time
+ (message "Next review in %d days"
+ (- (time-to-days scheduled-time)
+ (time-to-days (current-time))))
+ (sit-for 0.5)))))
+ (org-set-property "DRILL_LAST_QUALITY" (format "%d" quality))
+ (org-set-property "DRILL_LAST_REVIEWED"
+ (time-to-inactive-org-timestamp (current-time))))
quality))
((= ch ?e)
'edit)
(t
nil))))
-
;; (defun org-drill-hide-all-subheadings-except (heading-list)
;; "Returns a list containing the position of each immediate subheading of
;; the current topic."
@@ -1310,8 +1234,6 @@ How well did you do? (0-5, ?=help, e=edit, t=tags, q=quit)"
;; "" 'tree))
;; (reverse drill-sections)))
-
-
(defun org-drill-hide-subheadings-if (test)
"TEST is a function taking no arguments. TEST will be called for each
of the immediate subheadings of the current drill item, with the point
@@ -1334,13 +1256,11 @@ the current topic."
"" 'tree))
(reverse drill-sections)))
-
(defun org-drill-hide-all-subheadings-except (heading-list)
(org-drill-hide-subheadings-if
(lambda () (let ((drill-heading (org-get-heading t)))
(not (member drill-heading heading-list))))))
-
(defun org-drill-presentation-prompt (&rest fmt-and-args)
(let* ((item-start-time (current-time))
(input nil)
@@ -1361,9 +1281,13 @@ the current topic."
(format "%s %s %s %s %s %s"
(propertize
(char-to-string
- (case status
- (:new ?N) (:young ?Y) (:old ?o) (:overdue ?!)
- (:failed ?F) (t ??)))
+ (cond
+ ((eql status :failed) ?F)
+ (*org-drill-cram-mode* ?C)
+ (t
+ (case status
+ (:new ?N) (:young ?Y) (:old ?o) (:overdue ?!)
+ (t ??)))))
'face `(:foreground
,(case status
(:new org-drill-new-count-color)
@@ -1417,13 +1341,11 @@ Consider reformulating the item to make it easier to remember.\n"
(?s 'skip)
(otherwise t))))
-
(defun org-pos-in-regexp (pos regexp &optional nlines)
(save-excursion
(goto-char pos)
(org-in-regexp regexp nlines)))
-
(defun org-drill-hide-region (beg end &optional text)
"Hide the buffer region between BEG and END with an 'invisible text'
visual overlay, or with the string TEXT if it is supplied."
@@ -1435,22 +1357,19 @@ visual overlay, or with the string TEXT if it is supplied."
(overlay-put ovl 'face 'default)
(overlay-put ovl 'display text))))
-
(defun org-drill-hide-heading-at-point (&optional text)
(unless (org-at-heading-p)
- (error "Point is not on a heading"))
+ (error "Point is not on a heading."))
(save-excursion
(let ((beg (point)))
(end-of-line)
(org-drill-hide-region beg (point) text))))
-
(defun org-drill-hide-comments ()
(save-excursion
(while (re-search-forward "^#.*$" nil t)
(org-drill-hide-region (match-beginning 0) (match-end 0)))))
-
(defun org-drill-unhide-text ()
;; This will also unhide the item's heading.
(save-excursion
@@ -1458,7 +1377,6 @@ visual overlay, or with the string TEXT if it is supplied."
(when (eql 'org-drill-hidden-text-overlay (overlay-get ovl 'category))
(delete-overlay ovl)))))
-
(defun org-drill-hide-clozed-text ()
(save-excursion
(while (re-search-forward org-drill-cloze-regexp nil t)
@@ -1469,25 +1387,26 @@ visual overlay, or with the string TEXT if it is supplied."
org-bracket-link-regexp 1))
(org-drill-hide-matched-cloze-text)))))
-
(defun org-drill-hide-matched-cloze-text ()
"Hide the current match with a 'cloze' visual overlay."
- (let ((ovl (make-overlay (match-beginning 0) (match-end 0))))
+ (let ((ovl (make-overlay (match-beginning 0) (match-end 0)))
+ (hint-sep-pos (string-match-p (regexp-quote org-drill-hint-separator)
+ (match-string 0))))
(overlay-put ovl 'category
'org-drill-cloze-overlay-defaults)
- (when (find ?| (match-string 0))
+ (when (and hint-sep-pos
+ (> hint-sep-pos 1))
(let ((hint (substring-no-properties
(match-string 0)
- (1+ (position ?| (match-string 0)))
+ (+ hint-sep-pos (length org-drill-hint-separator))
(1- (length (match-string 0))))))
(overlay-put
ovl 'display
;; If hint is like `X...' then display [X...]
;; otherwise display [...X]
- (format (if (string-match-p "\\.\\.\\." hint) "[%s]" "[%s...]")
+ (format (if (string-match-p (regexp-quote "...") hint) "[%s]" "[%s...]")
hint))))))
-
(defun org-drill-hide-cloze-hints ()
(save-excursion
(while (re-search-forward org-drill-cloze-regexp nil t)
@@ -1497,7 +1416,6 @@ visual overlay, or with the string TEXT if it is supplied."
(null (match-beginning 2))) ; hint subexpression matched
(org-drill-hide-region (match-beginning 2) (match-end 2))))))
-
(defmacro with-replaced-entry-text (text &rest body)
"During the execution of BODY, the entire text of the current entry is
concealed by an overlay that displays the string TEXT."
@@ -1508,7 +1426,6 @@ concealed by an overlay that displays the string TEXT."
,@body)
(org-drill-unreplace-entry-text))))
-
(defmacro with-replaced-entry-text-multi (replacements &rest body)
"During the execution of BODY, the entire text of the current entry is
concealed by an overlay that displays the overlays in REPLACEMENTS."
@@ -1519,7 +1436,6 @@ concealed by an overlay that displays the overlays in REPLACEMENTS."
,@body)
(org-drill-unreplace-entry-text))))
-
(defun org-drill-replace-entry-text (text &optional multi-p)
"Make an overlay that conceals the entire text of the item, not
including properties or the contents of subheadings. The overlay shows
@@ -1542,14 +1458,12 @@ Note: does not actually alter the item."
'org-drill-replaced-text-overlay)
(overlay-put ovl 'display text)))))
-
(defun org-drill-unreplace-entry-text ()
(save-excursion
(dolist (ovl (overlays-in (point-min) (point-max)))
(when (eql 'org-drill-replaced-text-overlay (overlay-get ovl 'category))
(delete-overlay ovl)))))
-
(defun org-drill-replace-entry-text-multi (replacements)
"Make overlays that conceal the entire text of the item, not
including properties or the contents of subheadings. The overlay shows
@@ -1570,7 +1484,6 @@ Note: does not actually alter the item."
'org-drill-replaced-text-overlay)
(overlay-put ovl 'display (nth i replacements)))))
-
(defmacro with-replaced-entry-heading (heading &rest body)
`(progn
(org-drill-replace-entry-heading ,heading)
@@ -1579,21 +1492,18 @@ Note: does not actually alter the item."
,@body)
(org-drill-unhide-text))))
-
(defun org-drill-replace-entry-heading (heading)
"Make an overlay that conceals the heading of the item. The overlay shows
the string TEXT.
Note: does not actually alter the item."
(org-drill-hide-heading-at-point heading))
-
(defun org-drill-unhide-clozed-text ()
(save-excursion
(dolist (ovl (overlays-in (point-min) (point-max)))
(when (eql 'org-drill-cloze-overlay-defaults (overlay-get ovl 'category))
(delete-overlay ovl)))))
-
(defun org-drill-get-entry-text (&optional keep-properties-p)
(let ((text (org-agenda-get-some-entry-text (point-marker) 100)))
(if keep-properties-p
@@ -1601,13 +1511,23 @@ Note: does not actually alter the item."
(substring-no-properties text))))
-(defun org-drill-entry-empty-p ()
- (zerop (length (org-drill-get-entry-text))))
+;; (defun org-entry-empty-p ()
+;; (zerop (length (org-drill-get-entry-text))))
+;; This version is about 5x faster than the old version, above.
+(defun org-entry-empty-p ()
+ (save-excursion
+ (org-back-to-heading t)
+ (let ((lim (save-excursion
+ (outline-next-heading) (point))))
+ (org-end-of-meta-data-and-drawers)
+ (or (>= (point) lim)
+ (null (re-search-forward "[[:graph:]]" lim t))))))
+(defun org-drill-entry-empty-p () (org-entry-empty-p))
;;; Presentation functions ====================================================
-
+;;
;; Each of these is called with point on topic heading. Each needs to show the
;; topic in the form of a 'question' or with some information 'hidden', as
;; appropriate for the card type. The user should then be prompted to press a
@@ -1626,15 +1546,22 @@ Note: does not actually alter the item."
(prog1 (org-drill-presentation-prompt)
(org-drill-hide-subheadings-if 'org-drill-entry-p))))))
-
(defun org-drill-present-default-answer (reschedule-fn)
- (org-drill-hide-subheadings-if 'org-drill-entry-p)
- (org-drill-unhide-clozed-text)
- (ignore-errors
- (org-display-inline-images t))
- (with-hidden-cloze-hints
- (funcall reschedule-fn)))
-
+ (cond
+ (drill-answer
+ (with-replaced-entry-text
+ (format "\nAnswer:\n\n %s\n" drill-answer)
+ (prog1
+ (funcall reschedule-fn)
+ (setq drill-answer nil))))
+ (t
+ (org-drill-hide-subheadings-if 'org-drill-entry-p)
+ (org-drill-unhide-clozed-text)
+ (ignore-errors
+ (org-display-inline-images t))
+ (org-cycle-hide-drawers 'all)
+ (with-hidden-cloze-hints
+ (funcall reschedule-fn)))))
(defun org-drill-present-two-sided-card ()
(with-hidden-comments
@@ -1652,8 +1579,6 @@ Note: does not actually alter the item."
(prog1 (org-drill-presentation-prompt)
(org-drill-hide-subheadings-if 'org-drill-entry-p)))))))
-
-
(defun org-drill-present-multi-sided-card ()
(with-hidden-comments
(with-hidden-cloze-hints
@@ -1669,7 +1594,6 @@ Note: does not actually alter the item."
(prog1 (org-drill-presentation-prompt)
(org-drill-hide-subheadings-if 'org-drill-entry-p)))))))
-
(defun org-drill-present-multicloze-hide-n (number-to-hide
&optional
force-show-first
@@ -1749,7 +1673,6 @@ items if FORCE-SHOW-FIRST or FORCE-SHOW-LAST is non-nil)."
(org-drill-hide-subheadings-if 'org-drill-entry-p)
(org-drill-unhide-clozed-text))))))
-
(defun org-drill-present-multicloze-hide-nth (to-hide)
"Hide the TO-HIDE'th piece of clozed text. 1 is the first piece. If
TO-HIDE is negative, count backwards, so -1 means the last item, -2
@@ -1797,29 +1720,24 @@ the second to last, etc."
(org-drill-hide-subheadings-if 'org-drill-entry-p)
(org-drill-unhide-clozed-text))))))
-
(defun org-drill-present-multicloze-hide1 ()
"Hides one of the pieces of text that are marked for cloze deletion,
chosen at random."
(org-drill-present-multicloze-hide-n 1))
-
(defun org-drill-present-multicloze-hide2 ()
"Hides two of the pieces of text that are marked for cloze deletion,
chosen at random."
(org-drill-present-multicloze-hide-n 2))
-
(defun org-drill-present-multicloze-hide-first ()
"Hides the first piece of text that is marked for cloze deletion."
(org-drill-present-multicloze-hide-nth 1))
-
(defun org-drill-present-multicloze-hide-last ()
"Hides the last piece of text that is marked for cloze deletion."
(org-drill-present-multicloze-hide-nth -1))
-
(defun org-drill-present-multicloze-hide1-firstmore ()
"Commonly, hides the FIRST piece of text that is marked for
cloze deletion. Uncommonly, hide one of the other pieces of text,
@@ -1849,7 +1767,6 @@ the value of `org-drill-cloze-text-weight'."
;; Commonly, hide first item
(org-drill-present-multicloze-hide-first))))
-
(defun org-drill-present-multicloze-show1-lastmore ()
"Commonly, hides all pieces except the last. Uncommonly, shows
any random piece. The effect is similar to 'show1cloze' except
@@ -1874,7 +1791,6 @@ the value of `org-drill-cloze-text-weight'."
;; Commonly, show the LAST item
(org-drill-present-multicloze-hide-n -1 nil t))))
-
(defun org-drill-present-multicloze-show1-firstless ()
"Commonly, hides all pieces except one, where the shown piece
is guaranteed NOT to be the first piece. Uncommonly, shows any
@@ -1900,20 +1816,17 @@ the value of `org-drill-cloze-text-weight'."
;; Commonly, show any item, except the first
(org-drill-present-multicloze-hide-n -1 nil nil t))))
-
(defun org-drill-present-multicloze-show1 ()
"Similar to `org-drill-present-multicloze-hide1', but hides all
the pieces of text that are marked for cloze deletion, except for one
piece which is chosen at random."
(org-drill-present-multicloze-hide-n -1))
-
(defun org-drill-present-multicloze-show2 ()
"Similar to `org-drill-present-multicloze-show1', but reveals two
pieces rather than one."
(org-drill-present-multicloze-hide-n -2))
-
;; (defun org-drill-present-multicloze-show1 ()
;; "Similar to `org-drill-present-multicloze-hide1', but hides all
;; the pieces of text that are marked for cloze deletion, except for one
@@ -1947,12 +1860,13 @@ pieces rather than one."
;; (org-drill-hide-subheadings-if 'org-drill-entry-p)
;; (org-drill-unhide-clozed-text))))))
-
(defun org-drill-present-card-using-text (question &optional answer)
- "Present the string QUESTION as the only visible content of the card."
+ "Present the string QUESTION as the only visible content of the card.
+If ANSWER is supplied, set the global variable `drill-answer' to its value."
+ (if answer (setq drill-answer answer))
(with-hidden-comments
(with-replaced-entry-text
- question
+ (concat "\n" question)
(org-drill-hide-all-subheadings-except nil)
(org-cycle-hide-drawers 'all)
(ignore-errors
@@ -1960,11 +1874,12 @@ pieces rather than one."
(prog1 (org-drill-presentation-prompt)
(org-drill-hide-subheadings-if 'org-drill-entry-p)))))
-
(defun org-drill-present-card-using-multiple-overlays (replacements &optional answer)
"TEXTS is a list of valid values for the 'display' text property.
Present these overlays, in sequence, as the only
-visible content of the card."
+visible content of the card.
+If ANSWER is supplied, set the global variable `drill-answer' to its value."
+ (if answer (setq drill-answer answer))
(with-hidden-comments
(with-replaced-entry-text-multi
replacements
@@ -1975,7 +1890,6 @@ visible content of the card."
(prog1 (org-drill-presentation-prompt)
(org-drill-hide-subheadings-if 'org-drill-entry-p)))))
-
(defun org-drill-entry ()
"Present the current topic for interactive review, as in `org-drill'.
Review will occur regardless of whether the topic is due for review or whether
@@ -1995,20 +1909,24 @@ See `org-drill' for more details."
;; (org-back-to-heading))
(let ((card-type (org-entry-get (point) "DRILL_CARD_TYPE"))
(answer-fn 'org-drill-present-default-answer)
+ (present-empty-cards nil)
(cont nil)
;; fontification functions in `outline-view-change-hook' can cause big
;; slowdowns, so we temporarily bind this variable to nil here.
(outline-view-change-hook nil))
+ (setq drill-answer nil)
(org-save-outline-visibility t
(save-restriction
(org-narrow-to-subtree)
(org-show-subtree)
(org-cycle-hide-drawers 'all)
- (let ((presentation-fn (cdr (assoc card-type org-drill-card-type-alist))))
+ (let ((presentation-fn
+ (cdr (assoc card-type org-drill-card-type-alist))))
(if (listp presentation-fn)
(psetq answer-fn (or (second presentation-fn)
'org-drill-present-default-answer)
+ present-empty-cards (third presentation-fn)
presentation-fn (first presentation-fn)))
(cond
((null presentation-fn)
@@ -2031,9 +1949,9 @@ See `org-drill' for more details."
(funcall answer-fn
(lambda () (org-drill-reschedule)))))))))))))
-
(defun org-drill-entries-pending-p ()
(or *org-drill-again-entries*
+ *org-drill-current-item*
(and (not (org-drill-maximum-item-count-reached-p))
(not (org-drill-maximum-duration-reached-p))
(or *org-drill-new-entries*
@@ -2043,33 +1961,32 @@ See `org-drill' for more details."
*org-drill-overdue-entries*
*org-drill-again-entries*))))
-
(defun org-drill-pending-entry-count ()
- (+ (length *org-drill-new-entries*)
+ (+ (if (markerp *org-drill-current-item*) 1 0)
+ (length *org-drill-new-entries*)
(length *org-drill-failed-entries*)
(length *org-drill-young-mature-entries*)
(length *org-drill-old-mature-entries*)
(length *org-drill-overdue-entries*)
(length *org-drill-again-entries*)))
-
(defun org-drill-maximum-duration-reached-p ()
"Returns true if the current drill session has continued past its
maximum duration."
(and org-drill-maximum-duration
+ (not *org-drill-cram-mode*)
*org-drill-start-time*
(> (- (float-time (current-time)) *org-drill-start-time*)
(* org-drill-maximum-duration 60))))
-
(defun org-drill-maximum-item-count-reached-p ()
"Returns true if the current drill session has reached the
maximum number of items."
(and org-drill-maximum-items-per-session
+ (not *org-drill-cram-mode*)
(>= (length *org-drill-done-entries*)
org-drill-maximum-items-per-session)))
-
(defun org-drill-pop-next-pending-entry ()
(block org-drill-pop-next-pending-entry
(let ((m nil))
@@ -2117,7 +2034,6 @@ maximum number of items."
(return-from org-drill-pop-next-pending-entry nil)))))
m)))
-
(defun org-drill-entries (&optional resuming-p)
"Returns nil, t, or a list of markers representing entries that were
'failed' and need to be presented again before the session ends.
@@ -2157,6 +2073,7 @@ RESUMING-P is true if we are resuming a suspended drill session."
(setq end-pos (point-marker))
(return-from org-drill-entries nil))
((eql result 'skip)
+ (setq *org-drill-current-item* nil)
nil) ; skip this item
(t
(cond
@@ -2166,9 +2083,8 @@ RESUMING-P is true if we are resuming a suspended drill session."
(shuffle-list *org-drill-again-entries*)))
(push-end m *org-drill-again-entries*))
(t
- (push m *org-drill-done-entries*))))))))))))
-
-
+ (push m *org-drill-done-entries*)))
+ (setq *org-drill-current-item* nil))))))))))
(defun org-drill-final-report ()
(let ((pass-percent
@@ -2176,7 +2092,8 @@ RESUMING-P is true if we are resuming a suspended drill session."
(> qual org-drill-failure-quality))
*org-drill-session-qualities*))
(max 1 (length *org-drill-session-qualities*))))
- (prompt nil))
+ (prompt nil)
+ (max-mini-window-height 0.6))
(setq prompt
(format
"%d items reviewed. Session duration %s.
@@ -2255,10 +2172,7 @@ order to make items appear more frequently over time."
*org-drill-overdue-entry-count*
(round (* 100 *org-drill-overdue-entry-count*)
(+ *org-drill-dormant-entry-count*
- *org-drill-due-entry-count*)))
- ))))
-
-
+ *org-drill-due-entry-count*)))))))
(defun org-drill-free-markers (markers)
"MARKERS is a list of markers, all of which will be freed (set to
@@ -2305,8 +2219,14 @@ one of the following values:
(cond
((not (org-drill-entry-p))
nil)
- ((org-drill-entry-empty-p)
- nil) ; skip -- item body is empty
+ ((and (org-entry-empty-p)
+ (let* ((card-type (org-entry-get (point) "DRILL_CARD_TYPE" nil))
+ (dat (cdr (assoc card-type org-drill-card-type-alist))))
+ (or (null card-type)
+ (not (third dat)))))
+ ;; body is empty, and this is not a card type where empty bodies are
+ ;; meaningful, so skip it.
+ nil)
((null due) ; unscheduled - usually a skipped leech
:unscheduled)
;; ((eql -1 due)
@@ -2446,47 +2366,16 @@ than starting a new one."
(:overdue
(push (cons (point-marker) due) overdue-data))
(:old
- (push (point-marker) *org-drill-old-mature-entries*)))))))
+ (push (point-marker) *org-drill-old-mature-entries*))
+ )))))
scope)
- ;; (let ((due (org-drill-entry-days-overdue))
- ;; (last-int (org-drill-entry-last-interval 1)))
- ;; (cond
- ;; ((org-drill-entry-empty-p)
- ;; nil) ; skip -- item body is empty
- ;; ((or (null due) ; unscheduled - usually a skipped leech
- ;; (minusp due)) ; scheduled in the future
- ;; (incf *org-drill-dormant-entry-count*)
- ;; (if (eq -1 due)
- ;; (incf *org-drill-due-tomorrow-count*)))
- ;; ((org-drill-entry-new-p)
- ;; (push (point-marker) *org-drill-new-entries*))
- ;; ((<= (org-drill-entry-last-quality 9999)
- ;; org-drill-failure-quality)
- ;; ;; Mature entries that were failed last time are
- ;; ;; FAILED, regardless of how young, old or overdue
- ;; ;; they are.
- ;; (push (point-marker) *org-drill-failed-entries*))
- ;; ((org-drill-entry-overdue-p due last-int)
- ;; ;; Overdue status overrides young versus old
- ;; ;; distinction.
- ;; ;; Store marker + due, for sorting of overdue entries
- ;; (push (cons (point-marker) due) overdue-data))
- ;; ((<= (org-drill-entry-last-interval 9999)
- ;; org-drill-days-before-old)
- ;; ;; Item is 'young'.
- ;; (push (point-marker)
- ;; *org-drill-young-mature-entries*))
- ;; (t
- ;; (push (point-marker)
- ;; *org-drill-old-mature-entries*))))
- ;; Order 'overdue' items so that the most overdue will tend to
- ;; come up for review first, while keeping exact order random
(org-drill-order-overdue-entries overdue-data)
(setq *org-drill-overdue-entry-count*
(length *org-drill-overdue-entries*))))
(setq *org-drill-due-entry-count* (org-drill-pending-entry-count))
(cond
- ((and (null *org-drill-new-entries*)
+ ((and (null *org-drill-current-item*)
+ (null *org-drill-new-entries*)
(null *org-drill-failed-entries*)
(null *org-drill-overdue-entries*)
(null *org-drill-young-mature-entries*)
@@ -2497,6 +2386,7 @@ than starting a new one."
(message "Drill session finished!"))))
(progn
(unless end-pos
+ (setq *org-drill-cram-mode* nil)
(org-drill-free-markers *org-drill-done-entries*)))))
(cond
(end-pos
@@ -2515,8 +2405,7 @@ than starting a new one."
(org-drill-save-optimal-factor-matrix))
(if org-drill-save-buffers-after-drill-sessions-p
(save-some-buffers))
- (message "Drill session finished!")
- ))))
+ (message "Drill session finished!")))))
(defun org-drill-save-optimal-factor-matrix ()
@@ -2531,8 +2420,8 @@ all drill items are considered to be due for review, unless they
have been reviewed within the last `org-drill-cram-hours'
hours."
(interactive)
- (let ((*org-drill-cram-mode* t))
- (org-drill scope)))
+ (setq *org-drill-cram-mode* t)
+ (org-drill scope))
(defun org-drill-tree ()
@@ -2555,6 +2444,7 @@ were not reviewed during the last session, rather than scanning for
unreviewed items. If there are no leftover items in memory, a full
scan will be performed."
(interactive)
+ (setq *org-drill-cram-mode* nil)
(cond
((plusp (org-drill-pending-entry-count))
(org-drill-free-markers *org-drill-done-entries*)
@@ -2675,9 +2565,7 @@ the tag 'imported'."
(outline-next-heading)
(newline)
(forward-line -1)
- (paste-tree-here (1+ (or (org-current-level) 0)))
- )))))
-
+ (paste-tree-here (1+ (or (org-current-level) 0))))))))
(defun org-drill-merge-buffers (src &optional dest ignore-new-items-p)
@@ -2770,15 +2658,12 @@ copy them across."
(free-marker m))
*org-drill-dest-id-table*))))
-
-
;;; Card types for learning languages =========================================
;;; Get spell-number.el from:
;;; http://www.emacswiki.org/emacs/spell-number.el
(autoload 'spelln-integer-in-words "spell-number")
-
;;; `conjugate' card type =====================================================
;;; See spanish.org for usage
@@ -2883,19 +2768,120 @@ returns its return value."
(mood
(format "%s mood" mood))))
infinitive translation)
+ (org-cycle-hide-drawers 'all)
+ (funcall reschedule-fn))))
+
+
+;;; `decline_noun' card type ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defvar org-drill-noun-gender-alist
+ '(("masculine" "dodgerblue")
+ ("masc" "dodgerblue")
+ ("male" "dodgerblue")
+ ("m" "dodgerblue")
+ ("feminine" "orchid")
+ ("fem" "orchid")
+ ("female" "orchid")
+ ("f" "orchid")
+ ("neuter" "green")
+ ("neutral" "green")
+ ("neut" "green")
+ ("n" "green")
+ ))
+
+
+(defun org-drill-get-noun-info ()
+ "Auxiliary function used by `org-drill-present-noun-declension' and
+`org-drill-show-answer-noun-declension'."
+ (let ((noun (org-entry-get (point) "NOUN" t))
+ (noun-hint (org-entry-get (point) "NOUN_HINT" t))
+ (noun-root (org-entry-get (point) "NOUN_ROOT" t))
+ (noun-gender (org-entry-get (point) "NOUN_GENDER" t))
+ (translation (org-entry-get (point) "NOUN_TRANSLATION" t))
+ (highlight-face nil))
+ (unless (and noun translation)
+ (error "Missing information for `decline_noun' card (%s, %s, %s, %s) at %s"
+ noun translation noun-hint noun-root (point)))
+ (setq noun-root (if noun-root (car (read-from-string noun-root)))
+ noun (car (read-from-string noun))
+ noun-gender (downcase (car (read-from-string noun-gender)))
+ noun-hint (if noun-hint (car (read-from-string noun-hint)))
+ translation (car (read-from-string translation)))
+ (setq highlight-face
+ (list :foreground
+ (or (second (assoc-string noun-gender
+ org-drill-noun-gender-alist t))
+ "red")))
+ (setq noun (propertize noun 'face highlight-face))
+ (setq translation (propertize translation 'face highlight-face))
+ (list noun noun-root noun-gender noun-hint translation)))
+
+
+(defun org-drill-present-noun-declension ()
+ "Present a drill entry whose card type is 'decline_noun'."
+ (destructuring-bind (noun noun-root noun-gender noun-hint translation)
+ (org-drill-get-noun-info)
+ (let* ((props (org-entry-properties (point)))
+ (definite
+ (cond
+ ((assoc "DECLINE_DEFINITE" props)
+ (propertize (if (org-entry-get (point) "DECLINE_DEFINITE")
+ "definite" "indefinite")
+ 'face 'warning))
+ (t nil)))
+ (plural
+ (cond
+ ((assoc "DECLINE_PLURAL" props)
+ (propertize (if (org-entry-get (point) "DECLINE_PLURAL")
+ "plural" "singular")
+ 'face 'warning))
+ (t nil))))
+ (org-drill-present-card-using-text
+ (cond
+ ((zerop (random* 2))
+ (format "\nTranslate the noun\n\n%s (%s)\n\nand list its declensions%s.\n\n"
+ noun noun-gender
+ (if (or plural definite)
+ (format " for the %s %s form" definite plural)
+ "")))
+ (t
+ (format "\nGive the noun that means\n\n%s %s\n
+and list its declensions%s.\n\n"
+ translation
+ (if noun-hint (format " [HINT: %s]" noun-hint) "")
+ (if (or plural definite)
+ (format " for the %s %s form" definite plural)
+ ""))))))))
+
+
+(defun org-drill-show-answer-noun-declension (reschedule-fn)
+ "Show the answer for a drill item whose card type is 'decline_noun'.
+RESCHEDULE-FN must be a function that calls `org-drill-reschedule' and
+returns its return value."
+ (destructuring-bind (noun noun-root noun-gender noun-hint translation)
+ (org-drill-get-noun-info)
+ (with-replaced-entry-heading
+ (format "Declensions of %s (%s) ==> %s\n\n"
+ noun noun-gender translation)
+ (org-cycle-hide-drawers 'all)
(funcall reschedule-fn))))
;;; `translate_number' card type ==============================================
;;; See spanish.org for usage
-(defvar *drilled-number* 0)
-(defvar *drilled-number-direction* 'to-english)
+
+(defun spelln-integer-in-language (n lang)
+ (let ((spelln-language lang))
+ (spelln-integer-in-words n)))
(defun org-drill-present-translate-number ()
(let ((num-min (read (org-entry-get (point) "DRILL_NUMBER_MIN")))
(num-max (read (org-entry-get (point) "DRILL_NUMBER_MAX")))
(language (read (org-entry-get (point) "DRILL_LANGUAGE" t)))
+ (drilled-number 0)
+ (drilled-number-direction 'to-english)
(highlight-face 'font-lock-warning-face))
(cond
((not (fboundp 'spelln-integer-in-words))
@@ -2908,46 +2894,48 @@ returns its return value."
(if (> num-min num-max)
(psetf num-min num-max
num-max num-min))
- (setq *drilled-number*
+ (setq drilled-number
(+ num-min (random* (abs (1+ (- num-max num-min))))))
- (setq *drilled-number-direction*
+ (setq drilled-number-direction
(if (zerop (random* 2)) 'from-english 'to-english))
- (org-drill-present-card-using-text
- (if (eql 'to-english *drilled-number-direction*)
- (format "\nTranslate into English:\n\n%s\n"
- (let ((spelln-language language))
- (propertize
- (spelln-integer-in-words *drilled-number*)
- 'face highlight-face)))
+ (cond
+ ((eql 'to-english drilled-number-direction)
+ (org-drill-present-card-using-text
+ (format "\nTranslate into English:\n\n%s\n"
+ (propertize
+ (spelln-integer-in-language drilled-number language)
+ 'face highlight-face))
+ (spelln-integer-in-language drilled-number 'english-gb)))
+ (t
+ (org-drill-present-card-using-text
(format "\nTranslate into %s:\n\n%s\n"
(capitalize (format "%s" language))
- (let ((spelln-language 'english-gb))
- (propertize
- (spelln-integer-in-words *drilled-number*)
- 'face highlight-face)))))))))
-
-
-(defun org-drill-show-answer-translate-number (reschedule-fn)
- (let* ((language (read (org-entry-get (point) "DRILL_LANGUAGE" t)))
- (highlight-face 'font-lock-warning-face)
- (non-english
- (let ((spelln-language language))
- (propertize (spelln-integer-in-words *drilled-number*)
- 'face highlight-face)))
- (english
- (let ((spelln-language 'english-gb))
- (propertize (spelln-integer-in-words *drilled-number*)
- 'face 'highlight-face))))
- (with-replaced-entry-text
- (cond
- ((eql 'to-english *drilled-number-direction*)
- (format "\nThe English translation of %s is:\n\n%s\n"
- non-english english))
- (t
- (format "\nThe %s translation of %s is:\n\n%s\n"
- (capitalize (format "%s" language))
- english non-english)))
- (funcall reschedule-fn))))
+ (propertize
+ (spelln-integer-in-language drilled-number 'english-gb)
+ 'face highlight-face))
+ (spelln-integer-in-language drilled-number language))))))))
+
+;; (defun org-drill-show-answer-translate-number (reschedule-fn)
+;; (let* ((language (read (org-entry-get (point) "DRILL_LANGUAGE" t)))
+;; (highlight-face 'font-lock-warning-face)
+;; (non-english
+;; (let ((spelln-language language))
+;; (propertize (spelln-integer-in-words *drilled-number*)
+;; 'face highlight-face)))
+;; (english
+;; (let ((spelln-language 'english-gb))
+;; (propertize (spelln-integer-in-words *drilled-number*)
+;; 'face 'highlight-face))))
+;; (with-replaced-entry-text
+;; (cond
+;; ((eql 'to-english *drilled-number-direction*)
+;; (format "\nThe English translation of %s is:\n\n%s\n"
+;; non-english english))
+;; (t
+;; (format "\nThe %s translation of %s is:\n\n%s\n"
+;; (capitalize (format "%s" language))
+;; english non-english)))
+;; (funcall reschedule-fn))))
;;; `spanish_verb' card type ==================================================
diff --git a/contrib/lisp/org-e-ascii.el b/contrib/lisp/org-e-ascii.el
deleted file mode 100644
index ad0f1b3..0000000
--- a/contrib/lisp/org-e-ascii.el
+++ /dev/null
@@ -1,1807 +0,0 @@
-;;; org-e-ascii.el --- ASCII Back-End For Org Export Engine
-
-;; Copyright (C) 2012 Free Software Foundation, Inc.
-
-;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; This library implements an ASCII back-end for Org generic exporter.
-;;
-;; It provides two commands for export, depending on the desired
-;; output: `org-e-ascii-export-as-ascii' (temporary buffer) and
-;; `org-e-ascii-export-to-ascii' ("txt" file).
-;;
-;; Output encoding is specified through `org-e-ascii-charset'
-;; variable, among `ascii', `latin1' and `utf-8' symbols.
-;;
-;; By default, horizontal rules span over the full text with, but with
-;; a given width attribute (set though #+ATTR_ASCII: :width <num>)
-;; they can be shortened and centered.
-
-;;; Code:
-
-(eval-when-compile (require 'cl))
-(require 'org-export)
-
-(declare-function aa2u "ext:ascii-art-to-unicode" ())
-
-;;; Define Back-End
-;;
-;; The following setting won't allow to modify preferred charset
-;; through a buffer keyword or an option item, but, since the property
-;; will appear in communication channel nonetheless, it allows to
-;; override `org-e-ascii-charset' variable on the fly by the ext-plist
-;; mechanism.
-;;
-;; We also install a filter for headlines and sections, in order to
-;; control blank lines separating them in output string.
-
-(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)
- (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)))
-
-
-
-;;; User Configurable Variables
-
-(defgroup org-export-e-ascii nil
- "Options for exporting Org mode files to ASCII."
- :tag "Org Export ASCII"
- :group 'org-export)
-
-(defcustom org-e-ascii-text-width 72
- "Maximum width of exported text.
-This number includes margin size, as set in
-`org-e-ascii-global-margin'."
- :group 'org-export-e-ascii
- :type 'integer)
-
-(defcustom org-e-ascii-global-margin 0
- "Width of the left margin, in number of characters."
- :group 'org-export-e-ascii
- :type 'integer)
-
-(defcustom org-e-ascii-inner-margin 2
- "Width of the inner margin, in number of characters.
-Inner margin is applied between each headline."
- :group 'org-export-e-ascii
- :type 'integer)
-
-(defcustom org-e-ascii-quote-margin 6
- "Width of margin used for quoting text, in characters.
-This margin is applied on both sides of the text."
- :group 'org-export-e-ascii
- :type 'integer)
-
-(defcustom org-e-ascii-inlinetask-width 30
- "Width of inline tasks, in number of characters.
-This number ignores any margin."
- :group 'org-export-e-ascii
- :type 'integer)
-
-(defcustom org-e-ascii-headline-spacing '(1 . 2)
- "Number of blank lines inserted around headlines.
-
-This variable can be set to a cons cell. In that case, its car
-represents the number of blank lines present before headline
-contents whereas its cdr reflects the number of blank lines after
-contents.
-
-A nil value replicates the number of blank lines found in the
-original Org buffer at the same place."
- :group 'org-export-e-ascii
- :type '(choice
- (const :tag "Replicate original spacing" nil)
- (cons :tag "Set an uniform spacing"
- (integer :tag "Number of blank lines before contents")
- (integer :tag "Number of blank lines after contents"))))
-
-(defcustom org-e-ascii-charset 'ascii
- "The charset allowed to represent various elements and objects.
-Possible values are:
-`ascii' Only use plain ASCII characters
-`latin1' Include Latin-1 characters
-`utf-8' Use all UTF-8 characters"
- :group 'org-export-e-ascii
- :type '(choice
- (const :tag "ASCII" ascii)
- (const :tag "Latin-1" latin1)
- (const :tag "UTF-8" utf-8)))
-
-(defcustom org-e-ascii-underline '((ascii ?= ?~ ?-)
- (latin1 ?= ?~ ?-)
- (utf-8 ?═ ?─ ?╌ ?┄ ?┈))
- "Characters for underlining headings in ASCII export.
-
-Alist whose key is a symbol among `ascii', `latin1' and `utf-8'
-and whose value is a list of characters.
-
-For each supported charset, this variable associates a sequence
-of underline characters. In a sequence, the characters will be
-used in order for headlines level 1, 2, ... If no character is
-available for a given level, the headline won't be underlined."
- :group 'org-export-e-ascii
- :type '(list
- (cons :tag "Underline characters sequence"
- (const :tag "ASCII charset" ascii)
- (repeat character))
- (cons :tag "Underline characters sequence"
- (const :tag "Latin-1 charset" latin1)
- (repeat character))
- (cons :tag "Underline characters sequence"
- (const :tag "UTF-8 charset" utf-8)
- (repeat character))))
-
-(defcustom org-e-ascii-bullets '((ascii ?* ?+ ?-)
- (latin1 ?§ ?¶)
- (utf-8 ?◊))
- "Bullet characters for headlines converted to lists in ASCII export.
-
-Alist whose key is a symbol among `ascii', `latin1' and `utf-8'
-and whose value is a list of characters.
-
-The first character is used for the first level considered as low
-level, and so on. If there are more levels than characters given
-here, the list will be repeated.
-
-Note that this variable doesn't affect plain lists
-representation."
- :group 'org-export-e-ascii
- :type '(list
- (cons :tag "Bullet characters for low level headlines"
- (const :tag "ASCII charset" ascii)
- (repeat character))
- (cons :tag "Bullet characters for low level headlines"
- (const :tag "Latin-1 charset" latin1)
- (repeat character))
- (cons :tag "Bullet characters for low level headlines"
- (const :tag "UTF-8 charset" utf-8)
- (repeat character))))
-
-(defcustom org-e-ascii-links-to-notes t
- "Non-nil means convert links to notes before the next headline.
-When nil, the link will be exported in place. If the line
-becomes long in this way, it will be wrapped."
- :group 'org-export-e-ascii
- :type 'boolean)
-
-(defcustom org-e-ascii-table-keep-all-vertical-lines nil
- "Non-nil means keep all vertical lines in ASCII tables.
-When nil, vertical lines will be removed except for those needed
-for column grouping."
- :group 'org-export-e-ascii
- :type 'boolean)
-
-(defcustom org-e-ascii-table-widen-columns t
- "Non-nil means widen narrowed columns for export.
-When nil, narrowed columns will look in ASCII export just like in
-Org mode, i.e. with \"=>\" as ellipsis."
- :group 'org-export-e-ascii
- :type 'boolean)
-
-(defcustom org-e-ascii-table-use-ascii-art nil
- "Non-nil means table.el tables are turned into ascii-art.
-
-It only makes sense when export charset is `utf-8'. It is nil by
-default since it requires ascii-art-to-unicode.el package. You
-can download it here:
-
- http://gnuvola.org/software/j/aa2u/ascii-art-to-unicode.el.")
-
-(defcustom org-e-ascii-caption-above nil
- "When non-nil, place caption string before the element.
-Otherwise, place it right after it."
- :group 'org-export-e-ascii
- :type 'boolean)
-
-(defcustom org-e-ascii-verbatim-format "`%s'"
- "Format string used for verbatim text and inline code."
- :group 'org-export-e-ascii
- :type 'string)
-
-(defcustom org-e-ascii-format-drawer-function nil
- "Function called to format a drawer in ASCII.
-
-The function must accept two parameters:
- NAME the drawer name, like \"LOGBOOK\"
- CONTENTS the contents of the drawer.
- WIDTH the text width within the drawer.
-
-The function should return either the string to be exported or
-nil to ignore the drawer.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-ascii-format-drawer-default \(name contents width\)
- \"Format a drawer element for ASCII export.\"
- contents\)"
- :group 'org-export-e-ascii
- :type 'function)
-
-(defcustom org-e-ascii-format-inlinetask-function nil
- "Function called to format an inlinetask in ASCII.
-
-The function must accept six parameters:
- TODO the todo keyword, as a string
- TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
- PRIORITY the inlinetask priority, as a string
- NAME the inlinetask name, as a string.
- TAGS the inlinetask tags, as a list of strings.
- CONTENTS the contents of the inlinetask, as a string.
-
-The function should return either the string to be exported or
-nil to ignore the inline task.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-ascii-format-inlinetask-default
- \(todo type priority name tags contents\)
- \"Format an inline task element for ASCII export.\"
- \(let* \(\(utf8p \(eq \(plist-get info :ascii-charset\) 'utf-8\)\)
- \(width org-e-ascii-inlinetask-width\)
- \(org-e-ascii--indent-string
- \(concat
- ;; Top line, with an additional blank line if not in UTF-8.
- \(make-string width \(if utf8p ?━ ?_\)\) \"\\n\"
- \(unless utf8p \(concat \(make-string width ? \) \"\\n\"\)\)
- ;; Add title. Fill it if wider than inlinetask.
- \(let \(\(title \(org-e-ascii--build-title inlinetask info width\)\)\)
- \(if \(<= \(length title\) width\) title
- \(org-e-ascii--fill-string title width info\)\)\)
- \"\\n\"
- ;; If CONTENTS is not empty, insert it along with
- ;; a separator.
- \(when \(org-string-nw-p contents\)
- \(concat \(make-string width \(if utf8p ?─ ?-\)\) \"\\n\" contents\)\)
- ;; Bottom line.
- \(make-string width \(if utf8p ?━ ?_\)\)\)
- ;; Flush the inlinetask to the right.
- \(- \(plist-get info :ascii-width\)
- \(plist-get info :ascii-margin\)
- \(plist-get info :ascii-inner-margin\)
- \(org-e-ascii--current-text-width inlinetask info\)\)"
- :group 'org-export-e-ascii
- :type 'function)
-
-
-
-;;; Internal Functions
-
-;; Internal functions fall into three categories.
-
-;; The first one is about text formatting. The core function is
-;; `org-e-ascii--current-text-width', which determines the current
-;; text width allowed to a given element. In other words, it helps
-;; keeping each line width within maximum text width defined in
-;; `org-e-ascii-text-width'. Once this information is known,
-;; `org-e-ascii--fill-string', `org-e-ascii--justify-string',
-;; `org-e-ascii--box-string' and `org-e-ascii--indent-string' can
-;; operate on a given output string.
-
-;; The second category contains functions handling elements listings,
-;; triggered by "#+TOC:" keyword. As such, `org-e-ascii--build-toc'
-;; returns a complete table of contents, `org-e-ascii--list-listings'
-;; returns a list of referenceable src-block elements, and
-;; `org-e-ascii--list-tables' does the same for table elements.
-
-;; The third category includes general helper functions.
-;; `org-e-ascii--build-title' creates the title for a given headline
-;; or inlinetask element. `org-e-ascii--build-caption' returns the
-;; caption string associated to a table or a src-block.
-;; `org-e-ascii--describe-links' creates notes about links for
-;; insertion at the end of a section. It uses
-;; `org-e-ascii--unique-links' to get the list of links to describe.
-;; Eventually, `org-e-ascii--translate' translates a string according
-;; to language and charset specification.
-
-
-(defun org-e-ascii--fill-string (s text-width info &optional justify)
- "Fill a string with specified text-width and return it.
-
-S is the string being filled. TEXT-WIDTH is an integer
-specifying maximum length of a line. INFO is the plist used as
-a communication channel.
-
-Optional argument JUSTIFY can specify any type of justification
-among `left', `center', `right' or `full'. A nil value is
-equivalent to `left'. For a justification that doesn't also fill
-string, see `org-e-ascii--justify-string'.
-
-Return nil if S isn't a string."
- ;; Don't fill paragraph when break should be preserved.
- (cond ((not (stringp s)) nil)
- ((plist-get info :preserve-breaks) s)
- (t (with-temp-buffer
- (let ((fill-column text-width)
- (use-hard-newlines t))
- (insert s)
- (fill-region (point-min) (point-max) justify))
- (buffer-string)))))
-
-(defun org-e-ascii--justify-string (s text-width how)
- "Justify string S.
-TEXT-WIDTH is an integer specifying maximum length of a line.
-HOW determines the type of justification: it can be `left',
-`right', `full' or `center'."
- (with-temp-buffer
- (insert s)
- (goto-char (point-min))
- (let ((fill-column text-width))
- (while (< (point) (point-max))
- (justify-current-line how)
- (forward-line)))
- (buffer-string)))
-
-(defun org-e-ascii--indent-string (s width)
- "Indent string S by WIDTH white spaces.
-Empty lines are not indented."
- (when (stringp s)
- (replace-regexp-in-string
- "\\(^\\)\\(?:.*\\S-\\)" (make-string width ? ) s nil nil 1)))
-
-(defun org-e-ascii--box-string (s info)
- "Return string S with a partial box to its left.
-INFO is a plist used as a communicaton channel."
- (let ((utf8p (eq (plist-get info :ascii-charset) 'utf-8)))
- (format (if utf8p "╭────\n%s\n╰────" ",----\n%s\n`----")
- (replace-regexp-in-string
- "^" (if utf8p "│ " "| ")
- ;; Remove last newline character.
- (replace-regexp-in-string "\n[ \t]*\\'" "" s)))))
-
-(defun org-e-ascii--current-text-width (element info)
- "Return maximum text width for ELEMENT's contents.
-INFO is a plist used as a communication channel."
- (case (org-element-type element)
- ;; Elements with an absolute width: `headline' and `inlinetask'.
- (inlinetask org-e-ascii-inlinetask-width)
- ('headline
- (- org-e-ascii-text-width
- (let ((low-level-rank (org-export-low-level-p element info)))
- (if low-level-rank (* low-level-rank 2) org-e-ascii-global-margin))))
- ;; Elements with a relative width: store maximum text width in
- ;; TOTAL-WIDTH.
- (otherwise
- (let* ((genealogy (cons element (org-export-get-genealogy element)))
- ;; Total width is determined by the presence, or not, of an
- ;; inline task among ELEMENT parents.
- (total-width
- (if (loop for parent in genealogy
- thereis (eq (org-element-type parent) 'inlinetask))
- org-e-ascii-inlinetask-width
- ;; No inlinetask: Remove global margin from text width.
- (- org-e-ascii-text-width
- org-e-ascii-global-margin
- (let ((parent (org-export-get-parent-headline element)))
- ;; Inner margin doesn't apply to text before first
- ;; headline.
- (if (not parent) 0
- (let ((low-level-rank
- (org-export-low-level-p parent info)))
- ;; Inner margin doesn't apply to contents of
- ;; low level headlines, since they've got their
- ;; own indentation mechanism.
- (if low-level-rank (* low-level-rank 2)
- org-e-ascii-inner-margin))))))))
- (- total-width
- ;; Each `quote-block', `quote-section' and `verse-block' above
- ;; narrows text width by twice the standard margin size.
- (+ (* (loop for parent in genealogy
- when (memq (org-element-type parent)
- '(quote-block quote-section verse-block))
- count parent)
- 2 org-e-ascii-quote-margin)
- ;; Text width within a plain-list is restricted by
- ;; indentation of current item. If that's the case,
- ;; compute it with the help of `:structure' property from
- ;; parent item, if any.
- (let ((parent-item
- (if (eq (org-element-type element) 'item) element
- (loop for parent in genealogy
- when (eq (org-element-type parent) 'item)
- return parent))))
- (if (not parent-item) 0
- ;; Compute indentation offset of the current item,
- ;; that is the sum of the difference between its
- ;; indentation and the indentation of the top item in
- ;; the list and current item bullet's length. Also
- ;; remove checkbox length, and tag length (for
- ;; description lists) or bullet length.
- (let ((struct (org-element-property :structure parent-item))
- (beg-item (org-element-property :begin parent-item)))
- (+ (- (org-list-get-ind beg-item struct)
- (org-list-get-ind
- (org-list-get-top-point struct) struct))
- (length (org-e-ascii--checkbox parent-item info))
- (length
- (or (org-list-get-tag beg-item struct)
- (org-list-get-bullet beg-item struct)))))))))))))
-
-(defun org-e-ascii--build-title
- (element info text-width &optional underline notags)
- "Format ELEMENT title and return it.
-
-ELEMENT is either an `headline' or `inlinetask' element. INFO is
-a plist used as a communication channel. TEXT-WIDTH is an
-integer representing the maximum length of a line.
-
-When optional argument UNDERLINE is non-nil, underline title,
-without the tags, according to `org-e-ascii-underline'
-specifications.
-
-if optional argument NOTAGS is nil, no tags will be added to the
-title."
- (let* ((headlinep (eq (org-element-type element) 'headline))
- (numbers
- ;; Numbering is specific to headlines.
- (and headlinep (org-export-numbered-headline-p element info)
- ;; All tests passed: build numbering string.
- (concat
- (mapconcat
- 'number-to-string
- (org-export-get-headline-number element info) ".")
- " ")))
- (text (org-export-data (org-element-property :title element) info))
- (todo
- (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword element)))
- (and todo (concat (org-export-data todo info) " ")))))
- (tags (and (not notags)
- (plist-get info :with-tags)
- (let ((tag-list (org-export-get-tags element info)))
- (and tag-list
- (format ":%s:"
- (mapconcat 'identity tag-list ":"))))))
- (priority
- (and (plist-get info :with-priority)
- (let ((char (org-element-property :priority element)))
- (and char (format "(#%c) " char)))))
- (first-part (concat numbers todo priority text)))
- (concat
- first-part
- ;; Align tags, if any.
- (when tags
- (format
- (format " %%%ds"
- (max (- text-width (1+ (length first-part))) (length tags)))
- tags))
- ;; Maybe underline text, if ELEMENT type is `headline' and an
- ;; underline character has been defined.
- (when (and underline headlinep)
- (let ((under-char
- (nth (1- (org-export-get-relative-level element info))
- (cdr (assq (plist-get info :ascii-charset)
- org-e-ascii-underline)))))
- (and under-char
- (concat "\n"
- (make-string (length first-part) under-char))))))))
-
-(defun org-e-ascii--has-caption-p (element info)
- "Non-nil when ELEMENT has a caption affiliated keyword.
-INFO is a plist used as a communication channel. This function
-is meant to be used as a predicate for `org-export-get-ordinal'."
- (org-element-property :caption element))
-
-(defun org-e-ascii--build-caption (element info)
- "Return caption string for ELEMENT, if applicable.
-
-INFO is a plist used as a communication channel.
-
-The caption string contains the sequence number of ELEMENT along
-with its real caption. Return nil when ELEMENT has no affiliated
-caption keyword."
- (let ((caption (org-element-property :caption element)))
- (when caption
- ;; Get sequence number of current src-block among every
- ;; src-block with a caption.
- (let ((reference
- (org-export-get-ordinal
- element info nil 'org-e-ascii--has-caption-p))
- (title-fmt (org-e-ascii--translate
- (case (org-element-type element)
- (table "Table %d: %s")
- (src-block "Listing %d: %s"))
- info)))
- (org-e-ascii--fill-string
- (format title-fmt reference (org-export-data (car caption) info))
- (org-e-ascii--current-text-width element info) info)))))
-
-(defun org-e-ascii--build-toc (info &optional n keyword)
- "Return a table of contents.
-
-INFO is a plist used as a communication channel.
-
-Optional argument N, when non-nil, is an integer specifying the
-depth of the table.
-
-Optional argument KEYWORD specifies the TOC keyword, if any, from
-which the table of contents generation has been initiated."
- (let ((title (org-e-ascii--translate "Table of Contents" info)))
- (concat
- title "\n"
- (make-string (length title)
- (if (eq (plist-get info :ascii-charset) 'utf-8) ?─ ?_))
- "\n\n"
- (let ((text-width
- (if keyword (org-e-ascii--current-text-width keyword info)
- (- org-e-ascii-text-width org-e-ascii-global-margin))))
- (mapconcat
- (lambda (headline)
- (let* ((level (org-export-get-relative-level headline info))
- (indent (* (1- level) 3)))
- (concat
- (unless (zerop indent) (concat (make-string (1- indent) ?.) " "))
- (org-e-ascii--build-title
- headline info (- text-width indent) nil
- (eq (plist-get info :with-tags) 'not-in-toc)))))
- (org-export-collect-headlines info n) "\n")))))
-
-(defun org-e-ascii--list-listings (keyword info)
- "Return a list of listings.
-
-KEYWORD is the keyword that initiated the list of listings
-generation. INFO is a plist used as a communication channel."
- (let ((title (org-e-ascii--translate "List of Listings" info)))
- (concat
- title "\n"
- (make-string (length title)
- (if (eq (plist-get info :ascii-charset) 'utf-8) ?─ ?_))
- "\n\n"
- (let ((text-width
- (if keyword (org-e-ascii--current-text-width keyword info)
- (- org-e-ascii-text-width org-e-ascii-global-margin)))
- ;; Use a counter instead of retreiving ordinal of each
- ;; src-block.
- (count 0))
- (mapconcat
- (lambda (src-block)
- ;; Store initial text so its length can be computed. This is
- ;; used to properly align caption right to it in case of
- ;; filling (like contents of a description list item).
- (let ((initial-text
- (format (org-e-ascii--translate "Listing %d:" info)
- (incf count))))
- (concat
- initial-text " "
- (org-trim
- (org-e-ascii--indent-string
- (org-e-ascii--fill-string
- (let ((caption (org-element-property :caption src-block)))
- ;; Use short name in priority, if available.
- (org-export-data (or (cdr caption) (car caption)) info))
- (- text-width (length initial-text)) info)
- (length initial-text))))))
- (org-export-collect-listings info) "\n")))))
-
-(defun org-e-ascii--list-tables (keyword info)
- "Return a list of listings.
-
-KEYWORD is the keyword that initiated the list of listings
-generation. INFO is a plist used as a communication channel."
- (let ((title (org-e-ascii--translate "List of Tables" info)))
- (concat
- title "\n"
- (make-string (length title)
- (if (eq (plist-get info :ascii-charset) 'utf-8) ?─ ?_))
- "\n\n"
- (let ((text-width
- (if keyword (org-e-ascii--current-text-width keyword info)
- (- org-e-ascii-text-width org-e-ascii-global-margin)))
- ;; Use a counter instead of retreiving ordinal of each
- ;; src-block.
- (count 0))
- (mapconcat
- (lambda (table)
- ;; Store initial text so its length can be computed. This is
- ;; used to properly align caption right to it in case of
- ;; filling (like contents of a description list item).
- (let ((initial-text
- (format (org-e-ascii--translate "Table %d:" info)
- (incf count))))
- (concat
- initial-text " "
- (org-trim
- (org-e-ascii--indent-string
- (org-e-ascii--fill-string
- (let ((caption (org-element-property :caption table)))
- ;; Use short name in priority, if available.
- (org-export-data (or (cdr caption) (car caption)) info))
- (- text-width (length initial-text)) info)
- (length initial-text))))))
- (org-export-collect-tables info) "\n")))))
-
-(defun org-e-ascii--unique-links (element info)
- "Return a list of unique link references in ELEMENT.
-
-ELEMENT is either an headline element or a section element. INFO
-is a plist used as a communication channel."
- (let* (seen
- (unique-link-p
- (function
- ;; Return LINK if it wasn't referenced so far, or nil.
- ;; Update SEEN links along the way.
- (lambda (link)
- (let ((footprint
- (cons (org-element-property :raw-link link)
- (org-element-contents link))))
- (unless (member footprint seen)
- (push footprint seen) link)))))
- ;; If at a section, find parent headline, if any, in order to
- ;; count links that might be in the title.
- (headline
- (if (eq (org-element-type element) 'headline) element
- (or (org-export-get-parent-headline element) element))))
- ;; Get all links in HEADLINE.
- (org-element-map
- headline 'link (lambda (link) (funcall unique-link-p link)) info)))
-
-(defun org-e-ascii--describe-links (links width info)
- "Return a string describing a list of links.
-
-LINKS is a list of link type objects, as returned by
-`org-e-ascii--unique-links'. WIDTH is the text width allowed for
-the output string. INFO is a plist used as a communication
-channel."
- (mapconcat
- (lambda (link)
- (let ((type (org-element-property :type link))
- (anchor (let ((desc (org-element-contents link)))
- (if (not desc) (org-element-property :raw-link link)
- (org-export-data desc info)))))
- (cond
- ;; Coderefs, radio links and fuzzy links are ignored.
- ((member type '("coderef" "radio" "fuzzy")) nil)
- ;; Id and custom-id links: Headlines refer to their numbering.
- ((member type '("custom-id" "id"))
- (let ((dest (org-export-resolve-id-link link info)))
- (concat
- (org-e-ascii--fill-string
- (format
- "[%s] %s"
- anchor
- (if (not dest) (org-e-ascii--translate "Unknown reference" info)
- (format
- (org-e-ascii--translate "See section %s" info)
- (mapconcat 'number-to-string
- (org-export-get-headline-number dest info) "."))))
- width info) "\n\n")))
- ;; Do not add a link that cannot be resolved and doesn't have
- ;; any description: destination is already visible in the
- ;; paragraph.
- ((not (org-element-contents link)) nil)
- (t
- (concat
- (org-e-ascii--fill-string
- (format "[%s] %s" anchor (org-element-property :raw-link link))
- width info)
- "\n\n")))))
- links ""))
-
-(defun org-e-ascii--checkbox (item info)
- "Return checkbox string for ITEM or nil.
-INFO is a plist used as a communication channel."
- (let ((utf8p (eq (plist-get info :ascii-charset) 'utf-8)))
- (case (org-element-property :checkbox item)
- (on (if utf8p "☑ " "[X] "))
- (off (if utf8p "☐ " "[ ] "))
- (trans (if utf8p "☒ " "[-] ")))))
-
-
-
-;;; Template
-
-(defun org-e-ascii-template--document-title (info)
- "Return document title, as a string.
-INFO is a plist used as a communication channel."
- (let ((text-width org-e-ascii-text-width)
- (title (org-export-data (plist-get info :title) info))
- (author (and (plist-get info :with-author)
- (let ((auth (plist-get info :author)))
- (and auth (org-export-data auth info)))))
- (email (and (plist-get info :with-email)
- (org-export-data (plist-get info :email) info)))
- (date (org-export-data (plist-get info :date) info)))
- ;; There are two types of title blocks depending on the presence
- ;; of a title to display.
- (if (string= title "")
- ;; Title block without a title. DATE is positioned at the top
- ;; right of the document, AUTHOR to the top left and EMAIL
- ;; just below.
- (cond
- ((and (org-string-nw-p date) (org-string-nw-p author))
- (concat
- author
- (make-string (- text-width (length date) (length author)) ? )
- date
- (when (org-string-nw-p email) (concat "\n" email))
- "\n\n\n"))
- ((and (org-string-nw-p date) (org-string-nw-p email))
- (concat
- email
- (make-string (- text-width (length date) (length email)) ? )
- date "\n\n\n"))
- ((org-string-nw-p date)
- (concat
- (org-e-ascii--justify-string date text-width 'right)
- "\n\n\n"))
- ((and (org-string-nw-p author) (org-string-nw-p email))
- (concat author "\n" email "\n\n\n"))
- ((org-string-nw-p author) (concat author "\n\n\n"))
- ((org-string-nw-p email) (concat email "\n\n\n")))
- ;; Title block with a title. Document's TITLE, along with the
- ;; AUTHOR and its EMAIL are both overlined and an underlined,
- ;; centered. Date is just below, also centered.
- (let* ((utf8p (eq (plist-get info :ascii-charset) 'utf-8))
- ;; Format TITLE. It may be filled if it is too wide,
- ;; that is wider than the two thirds of the total width.
- (title-len (min (length title) (/ (* 2 text-width) 3)))
- (formatted-title (org-e-ascii--fill-string title title-len info))
- (line
- (make-string
- (min (+ (max title-len (length author) (length email)) 2)
- text-width) (if utf8p ?━ ?_))))
- (org-e-ascii--justify-string
- (concat line "\n"
- (unless utf8p "\n")
- (upcase formatted-title)
- (cond
- ((and (org-string-nw-p author) (org-string-nw-p email))
- (concat (if utf8p "\n\n\n" "\n\n") author "\n" email))
- ((org-string-nw-p author)
- (concat (if utf8p "\n\n\n" "\n\n") author))
- ((org-string-nw-p email)
- (concat (if utf8p "\n\n\n" "\n\n") email)))
- "\n" line
- (when (org-string-nw-p date) (concat "\n\n\n" date))
- "\n\n\n") text-width 'center)))))
-
-(defun org-e-ascii-template (contents info)
- "Return complete document string after ASCII conversion.
-CONTENTS is the transcoded contents string. INFO is a plist
-holding export options."
- (org-element-normalize-string
- (org-e-ascii--indent-string
- (let ((text-width (- org-e-ascii-text-width org-e-ascii-global-margin)))
- ;; 1. Build title block.
- (concat
- (org-e-ascii-template--document-title info)
- ;; 2. Table of contents.
- (let ((depth (plist-get info :with-toc)))
- (when depth
- (concat
- (org-e-ascii--build-toc info (and (wholenump depth) depth))
- "\n\n\n")))
- ;; 3. Document's body.
- contents
- ;; 4. Footnote definitions.
- (let ((definitions (org-export-collect-footnote-definitions
- (plist-get info :parse-tree) info))
- ;; Insert full links right inside the footnote definition
- ;; as they have no chance to be inserted later.
- (org-e-ascii-links-to-notes nil))
- (when definitions
- (concat
- "\n\n\n"
- (let ((title (org-e-ascii--translate "Footnotes" info)))
- (concat
- title "\n"
- (make-string
- (length title)
- (if (eq (plist-get info :ascii-charset) 'utf-8) ?─ ?_))))
- "\n\n"
- (mapconcat
- (lambda (ref)
- (let ((id (format "[%s] " (car ref))))
- ;; Distinguish between inline definitions and
- ;; full-fledged definitions.
- (org-trim
- (let ((def (nth 2 ref)))
- (if (eq (org-element-type def) 'org-data)
- ;; Full-fledged definition: footnote ID is
- ;; inserted inside the first parsed paragraph
- ;; (FIRST), if any, to be sure filling will
- ;; take it into consideration.
- (let ((first (car (org-element-contents def))))
- (if (not (eq (org-element-type first) 'paragraph))
- (concat id "\n" (org-export-data def info))
- (push id (nthcdr 2 first))
- (org-export-data def info)))
- ;; Fill paragraph once footnote ID is inserted in
- ;; order to have a correct length for first line.
- (org-e-ascii--fill-string
- (concat id (org-export-data def info))
- text-width info))))))
- definitions "\n\n"))))
- ;; 5. Creator. Ignore `comment' value as there are no comments in
- ;; ASCII. Justify it to the bottom right.
- (let ((creator-info (plist-get info :with-creator)))
- (unless (or (not creator-info) (eq creator-info 'comment))
- (concat
- "\n\n\n"
- (org-e-ascii--fill-string
- (plist-get info :creator) text-width info 'right))))))
- org-e-ascii-global-margin)))
-
-(defun org-e-ascii--translate (s info)
- "Translate string S according to specified language and charset.
-INFO is a plist used as a communication channel."
- (let ((charset (intern (format ":%s" (plist-get info :ascii-charset)))))
- (org-export-translate s charset info)))
-
-
-
-;;; Transcode Functions
-
-;;;; Babel Call
-
-;; Babel Calls are ignored.
-
-
-;;;; Bold
-
-(defun org-e-ascii-bold (bold contents info)
- "Transcode BOLD from Org to ASCII.
-CONTENTS is the text with bold markup. INFO is a plist holding
-contextual information."
- (format "*%s*" contents))
-
-
-;;;; Center Block
-
-(defun org-e-ascii-center-block (center-block contents info)
- "Transcode a CENTER-BLOCK element from Org to ASCII.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (org-e-ascii--justify-string
- contents (org-e-ascii--current-text-width center-block info) 'center))
-
-
-;;;; Clock
-
-(defun org-e-ascii-clock (clock contents info)
- "Transcode a CLOCK object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (concat org-clock-string " "
- (org-translate-time (org-element-property :value clock))
- (let ((time (org-element-property :time clock)))
- (and time
- (concat " => "
- (apply 'format
- "%2s:%02s"
- (org-split-string time ":")))))))
-
-
-;;;; Code
-
-(defun org-e-ascii-code (code contents info)
- "Return a CODE object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format org-e-ascii-verbatim-format (org-element-property :value code)))
-
-
-;;;; Comment
-
-;; Comments are ignored.
-
-
-;;;; Comment Block
-
-;; Comment Blocks are ignored.
-
-
-;;;; Drawer
-
-(defun org-e-ascii-drawer (drawer contents info)
- "Transcode a DRAWER element from Org to ASCII.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((name (org-element-property :drawer-name drawer))
- (width (org-e-ascii--current-text-width drawer info)))
- (if (functionp org-e-ascii-format-drawer-function)
- (funcall org-e-ascii-format-drawer-function name contents width)
- ;; If there's no user defined function: simply
- ;; display contents of the drawer.
- contents)))
-
-
-;;;; Dynamic Block
-
-(defun org-e-ascii-dynamic-block (dynamic-block contents info)
- "Transcode a DYNAMIC-BLOCK element from Org to ASCII.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- contents)
-
-
-;;;; Entity
-
-(defun org-e-ascii-entity (entity contents info)
- "Transcode an ENTITY object from Org to ASCII.
-CONTENTS are the definition itself. INFO is a plist holding
-contextual information."
- (org-element-property
- (intern (concat ":" (symbol-name (plist-get info :ascii-charset))))
- entity))
-
-
-;;;; Example Block
-
-(defun org-e-ascii-example-block (example-block contents info)
- "Transcode a EXAMPLE-BLOCK element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-ascii--box-string
- (org-export-format-code-default example-block info) info))
-
-
-;;;; Export Snippet
-
-(defun org-e-ascii-export-snippet (export-snippet contents info)
- "Transcode a EXPORT-SNIPPET object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (eq (org-export-snippet-backend export-snippet) 'e-ascii)
- (org-element-property :value export-snippet)))
-
-
-;;;; Export Block
-
-(defun org-e-ascii-export-block (export-block contents info)
- "Transcode a EXPORT-BLOCK element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (string= (org-element-property :type export-block) "ASCII")
- (org-remove-indentation (org-element-property :value export-block))))
-
-
-;;;; Fixed Width
-
-(defun org-e-ascii-fixed-width (fixed-width contents info)
- "Transcode a FIXED-WIDTH element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-ascii--box-string
- (org-remove-indentation
- (org-element-property :value fixed-width)) info))
-
-
-;;;; Footnote Definition
-
-;; Footnote Definitions are ignored. They are compiled at the end of
-;; the document, by `org-e-ascii-template'.
-
-
-;;;; Footnote Reference
-
-(defun org-e-ascii-footnote-reference (footnote-reference contents info)
- "Transcode a FOOTNOTE-REFERENCE element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (format "[%s]" (org-export-get-footnote-number footnote-reference info)))
-
-
-;;;; Headline
-
-(defun org-e-ascii-headline (headline contents info)
- "Transcode an HEADLINE element from Org to ASCII.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- ;; Don't export footnote section, which will be handled at the end
- ;; of the template.
- (unless (org-element-property :footnote-section-p headline)
- (let* ((low-level-rank (org-export-low-level-p headline info))
- (width (org-e-ascii--current-text-width headline info))
- ;; Blank lines between headline and its contents.
- ;; `org-e-ascii-headline-spacing', when set, overwrites
- ;; original buffer's spacing.
- (pre-blanks
- (make-string
- (if org-e-ascii-headline-spacing (car org-e-ascii-headline-spacing)
- (org-element-property :pre-blank headline)) ?\n))
- ;; Even if HEADLINE has no section, there might be some
- ;; links in its title that we shouldn't forget to describe.
- (links
- (unless (or (eq (caar (org-element-contents headline)) 'section))
- (let ((title (org-element-property :title headline)))
- (when (consp title)
- (org-e-ascii--describe-links
- (org-e-ascii--unique-links title info) width info))))))
- ;; Deep subtree: export it as a list item.
- (if low-level-rank
- (concat
- ;; Bullet.
- (let ((bullets (cdr (assq (plist-get info :ascii-charset)
- org-e-ascii-bullets))))
- (char-to-string
- (nth (mod (1- low-level-rank) (length bullets)) bullets)))
- " "
- ;; Title.
- (org-e-ascii--build-title headline info width) "\n"
- ;; Contents, indented by length of bullet.
- pre-blanks
- (org-e-ascii--indent-string
- (concat contents
- (when (org-string-nw-p links) (concat "\n\n" links)))
- 2))
- ;; Else: Standard headline.
- (concat
- (org-e-ascii--build-title headline info width 'underline)
- "\n" pre-blanks
- (concat (when (org-string-nw-p links) links) contents))))))
-
-
-;;;; Horizontal Rule
-
-(defun org-e-ascii-horizontal-rule (horizontal-rule contents info)
- "Transcode an HORIZONTAL-RULE object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (let ((text-width (org-e-ascii--current-text-width horizontal-rule info))
- (spec-width
- (org-export-read-attribute :attr_ascii horizontal-rule :width)))
- (org-e-ascii--justify-string
- (make-string (if (wholenump spec-width) spec-width text-width)
- (if (eq (plist-get info :ascii-charset) 'utf-8) ?― ?-))
- text-width 'center)))
-
-
-;;;; Inline Babel Call
-
-;; Inline Babel Calls are ignored.
-
-
-;;;; Inline Src Block
-
-(defun org-e-ascii-inline-src-block (inline-src-block contents info)
- "Transcode an INLINE-SRC-BLOCK element from Org to ASCII.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (format org-e-ascii-verbatim-format
- (org-element-property :value inline-src-block)))
-
-
-;;;; Inlinetask
-
-(defun org-e-ascii-inlinetask (inlinetask contents info)
- "Transcode an INLINETASK element from Org to ASCII.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((width (org-e-ascii--current-text-width inlinetask info)))
- ;; If `org-e-ascii-format-inlinetask-function' is provided, call it
- ;; with appropriate arguments.
- (if (functionp org-e-ascii-format-inlinetask-function)
- (funcall org-e-ascii-format-inlinetask-function
- ;; todo.
- (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property
- :todo-keyword inlinetask)))
- (and todo (org-export-data todo info))))
- ;; todo-type
- (org-element-property :todo-type inlinetask)
- ;; priority
- (and (plist-get info :with-priority)
- (org-element-property :priority inlinetask))
- ;; title
- (org-export-data (org-element-property :title inlinetask) info)
- ;; tags
- (and (plist-get info :with-tags)
- (org-element-property :tags inlinetask))
- ;; contents and width
- contents width)
- ;; Otherwise, use a default template.
- (let* ((utf8p (eq (plist-get info :ascii-charset) 'utf-8)))
- (org-e-ascii--indent-string
- (concat
- ;; Top line, with an additional blank line if not in UTF-8.
- (make-string width (if utf8p ?━ ?_)) "\n"
- (unless utf8p (concat (make-string width ? ) "\n"))
- ;; Add title. Fill it if wider than inlinetask.
- (let ((title (org-e-ascii--build-title inlinetask info width)))
- (if (<= (length title) width) title
- (org-e-ascii--fill-string title width info)))
- "\n"
- ;; If CONTENTS is not empty, insert it along with
- ;; a separator.
- (when (org-string-nw-p contents)
- (concat (make-string width (if utf8p ?─ ?-)) "\n" contents))
- ;; Bottom line.
- (make-string width (if utf8p ?━ ?_)))
- ;; Flush the inlinetask to the right.
- (- org-e-ascii-text-width org-e-ascii-global-margin
- (if (not (org-export-get-parent-headline inlinetask)) 0
- org-e-ascii-inner-margin)
- (org-e-ascii--current-text-width inlinetask info)))))))
-
-;;;; Italic
-
-(defun org-e-ascii-italic (italic contents info)
- "Transcode italic from Org to ASCII.
-CONTENTS is the text with italic markup. INFO is a plist holding
-contextual information."
- (format "/%s/" contents))
-
-
-;;;; Item
-
-(defun org-e-ascii-item (item contents info)
- "Transcode an ITEM element from Org to ASCII.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((utf8p (eq (plist-get info :ascii-charset) 'utf-8))
- (checkbox (org-e-ascii--checkbox item info))
- (list-type (org-element-property :type (org-export-get-parent item)))
- (bullet
- ;; First parent of ITEM is always the plain-list. Get
- ;; `:type' property from it.
- (org-list-bullet-string
- (case list-type
- (descriptive
- (concat checkbox
- (org-export-data (org-element-property :tag item) info)
- ": "))
- (ordered
- ;; Return correct number for ITEM, paying attention to
- ;; counters.
- (let* ((struct (org-element-property :structure item))
- (bul (org-element-property :bullet item))
- (num (number-to-string
- (car (last (org-list-get-item-number
- (org-element-property :begin item)
- struct
- (org-list-prevs-alist struct)
- (org-list-parents-alist struct)))))))
- (replace-regexp-in-string "[0-9]+" num bul)))
- (t (let ((bul (org-element-property :bullet item)))
- ;; Change bullets into more visible form if UTF-8 is active.
- (if (not utf8p) bul
- (replace-regexp-in-string
- "-" "•"
- (replace-regexp-in-string
- "+" "⁃"
- (replace-regexp-in-string "*" "‣" bul))))))))))
- (concat
- bullet
- (unless (eq list-type 'descriptive) checkbox)
- ;; Contents: Pay attention to indentation. Note: check-boxes are
- ;; already taken care of at the paragraph level so they don't
- ;; interfere with indentation.
- (let ((contents (org-e-ascii--indent-string contents (length bullet))))
- (if (eq (org-element-type (car (org-element-contents item))) 'paragraph)
- (org-trim contents)
- (concat "\n" contents))))))
-
-
-;;;; Keyword
-
-(defun org-e-ascii-keyword (keyword contents info)
- "Transcode a KEYWORD element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (let ((key (org-element-property :key keyword))
- (value (org-element-property :value keyword)))
- (cond
- ((string= key "ASCII") value)
- ((string= key "TOC")
- (let ((value (downcase value)))
- (cond
- ((string-match "\\<headlines\\>" value)
- (let ((depth (or (and (string-match "[0-9]+" value)
- (string-to-number (match-string 0 value)))
- (plist-get info :with-toc))))
- (org-e-ascii--build-toc
- info (and (wholenump depth) depth) keyword)))
- ((string= "tables" value)
- (org-e-ascii--list-tables keyword info))
- ((string= "listings" value)
- (org-e-ascii--list-listings keyword info))))))))
-
-
-;;;; Latex Environment
-
-(defun org-e-ascii-latex-environment (latex-environment contents info)
- "Transcode a LATEX-ENVIRONMENT element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (org-remove-indentation (org-element-property :value latex-environment)))
-
-
-;;;; Latex Fragment
-
-(defun org-e-ascii-latex-fragment (latex-fragment contents info)
- "Transcode a LATEX-FRAGMENT object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (org-element-property :value latex-fragment))
-
-
-;;;; Line Break
-
-(defun org-e-ascii-line-break (line-break contents info)
- "Transcode a LINE-BREAK object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
- information." hard-newline)
-
-
-;;;; Link
-
-(defun org-e-ascii-link (link desc info)
- "Transcode a LINK object from Org to ASCII.
-
-DESC is the description part of the link, or the empty string.
-INFO is a plist holding contextual information."
- (let ((raw-link (org-element-property :raw-link link))
- (type (org-element-property :type link)))
- (cond
- ((string= type "coderef")
- (let ((ref (org-element-property :path link)))
- (format (org-export-get-coderef-format ref desc)
- (org-export-resolve-coderef ref info))))
- ;; Do not apply a special syntax on radio links. Though, use
- ;; transcoded target's contents as output.
- ((string= type "radio")
- (let ((destination (org-export-resolve-radio-link link info)))
- (when destination
- (org-export-data (org-element-contents destination) info))))
- ;; Do not apply a special syntax on fuzzy links pointing to
- ;; targets.
- ((string= type "fuzzy")
- (let ((destination (org-export-resolve-fuzzy-link link info)))
- ;; Ignore invisible "#+TARGET: path".
- (unless (eq (org-element-type destination) 'keyword)
- (if (org-string-nw-p desc) desc
- (when destination
- (let ((number
- (org-export-get-ordinal
- destination info nil 'org-e-ascii--has-caption-p)))
- (when number
- (if (atom number) (number-to-string number)
- (mapconcat 'number-to-string number ".")))))))))
- (t
- (if (not (org-string-nw-p desc)) (format "[%s]" raw-link)
- (concat
- (format "[%s]" desc)
- (unless org-e-ascii-links-to-notes (format " (%s)" raw-link))))))))
-
-
-;;;; Macro
-
-(defun org-e-ascii-macro (macro contents info)
- "Transcode a MACRO element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (org-export-expand-macro macro info))
-
-
-;;;; Paragraph
-
-(defun org-e-ascii-paragraph (paragraph contents info)
- "Transcode a PARAGRAPH element from Org to ASCII.
-CONTENTS is the contents of the paragraph, as a string. INFO is
-the plist used as a communication channel."
- (org-e-ascii--fill-string
- contents
- (org-e-ascii--current-text-width paragraph info) info))
-
-
-;;;; Plain List
-
-(defun org-e-ascii-plain-list (plain-list contents info)
- "Transcode a PLAIN-LIST element from Org to ASCII.
-CONTENTS is the contents of the list. INFO is a plist holding
-contextual information."
- contents)
-
-
-;;;; Plain Text
-
-(defun org-e-ascii-plain-text (text info)
- "Transcode a TEXT string from Org to ASCII.
-INFO is a plist used as a communication channel."
- (if (not (and (eq (plist-get info :ascii-charset) 'utf-8)
- (plist-get info :with-special-strings)))
- text
- ;; Usual replacements in utf-8 with proper option set.
- (replace-regexp-in-string
- "\\.\\.\\." "…"
- (replace-regexp-in-string
- "--" "–"
- (replace-regexp-in-string "---" "—" text)))))
-
-
-;;;; Planning
-
-(defun org-e-ascii-planning (planning contents info)
- "Transcode a PLANNING element from Org to ASCII.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (mapconcat
- 'identity
- (delq nil
- (list (let ((closed (org-element-property :closed planning)))
- (when closed (concat org-closed-string " "
- (org-translate-time closed))))
- (let ((deadline (org-element-property :deadline planning)))
- (when deadline (concat org-deadline-string " "
- (org-translate-time deadline))))
- (let ((scheduled (org-element-property :scheduled planning)))
- (when scheduled (concat org-scheduled-string " "
- (org-translate-time scheduled))))))
- " "))
-
-
-;;;; Property Drawer
-;;
-;; Property drawers are ignored.
-
-
-;;;; Quote Block
-
-(defun org-e-ascii-quote-block (quote-block contents info)
- "Transcode a QUOTE-BLOCK element from Org to ASCII.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((width (org-e-ascii--current-text-width quote-block info)))
- (org-e-ascii--indent-string
- (org-remove-indentation
- (org-e-ascii--fill-string contents width info))
- org-e-ascii-quote-margin)))
-
-
-;;;; Quote Section
-
-(defun org-e-ascii-quote-section (quote-section contents info)
- "Transcode a QUOTE-SECTION element from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((width (org-e-ascii--current-text-width quote-section info))
- (value
- (org-export-data
- (org-remove-indentation (org-element-property :value quote-section))
- info)))
- (org-e-ascii--indent-string
- value
- (+ org-e-ascii-quote-margin
- ;; Don't apply inner margin if parent headline is low level.
- (let ((headline (org-export-get-parent-headline quote-section)))
- (if (org-export-low-level-p headline info) 0
- org-e-ascii-inner-margin))))))
-
-
-;;;; Radio Target
-
-(defun org-e-ascii-radio-target (radio-target contents info)
- "Transcode a RADIO-TARGET object from Org to ASCII.
-CONTENTS is the contents of the target. INFO is a plist holding
-contextual information."
- contents)
-
-;;;; Section
-
-(defun org-e-ascii-section (section contents info)
- "Transcode a SECTION element from Org to ASCII.
-CONTENTS is the contents of the section. INFO is a plist holding
-contextual information."
- (org-e-ascii--indent-string
- (concat
- contents
- (when org-e-ascii-links-to-notes
- ;; Add list of links at the end of SECTION.
- (let ((links (org-e-ascii--describe-links
- (org-e-ascii--unique-links section info)
- (org-e-ascii--current-text-width section info) info)))
- ;; Separate list of links and section contents.
- (when (org-string-nw-p links) (concat "\n\n" links)))))
- ;; Do not apply inner margin if parent headline is low level.
- (let ((headline (org-export-get-parent-headline section)))
- (if (or (not headline) (org-export-low-level-p headline info)) 0
- org-e-ascii-inner-margin))))
-
-
-;;;; Special Block
-
-(defun org-e-ascii-special-block (special-block contents info)
- "Transcode a SPECIAL-BLOCK element from Org to ASCII.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- contents)
-
-
-;;;; Src Block
-
-(defun org-e-ascii-src-block (src-block contents info)
- "Transcode a SRC-BLOCK element from Org to ASCII.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let ((caption (org-e-ascii--build-caption src-block info)))
- (concat
- (when (and caption org-e-ascii-caption-above) (concat caption "\n"))
- (org-e-ascii--box-string
- (org-export-format-code-default src-block info) info)
- (when (and caption (not org-e-ascii-caption-above))
- (concat "\n" caption)))))
-
-;;;; Statistics Cookie
-
-(defun org-e-ascii-statistics-cookie (statistics-cookie contents info)
- "Transcode a STATISTICS-COOKIE object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-element-property :value statistics-cookie))
-
-
-;;;; Subscript
-
-(defun org-e-ascii-subscript (subscript contents info)
- "Transcode a SUBSCRIPT object from Org to ASCII.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (if (org-element-property :use-brackets-p subscript)
- (format "_{%s}" contents)
- (format "_%s" contents)))
-
-
-;;;; Superscript
-
-(defun org-e-ascii-superscript (superscript contents info)
- "Transcode a SUPERSCRIPT object from Org to ASCII.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (if (org-element-property :use-brackets-p superscript)
- (format "_{%s}" contents)
- (format "_%s" contents)))
-
-
-;;;; Strike-through
-
-(defun org-e-ascii-strike-through (strike-through contents info)
- "Transcode STRIKE-THROUGH from Org to ASCII.
-CONTENTS is text with strike-through markup. INFO is a plist
-holding contextual information."
- (format "+%s+" contents))
-
-
-;;;; Table
-
-(defun org-e-ascii-table (table contents info)
- "Transcode a TABLE element from Org to ASCII.
-CONTENTS is the contents of the table. INFO is a plist holding
-contextual information."
- (let ((caption (org-e-ascii--build-caption table info)))
- (concat
- ;; Possibly add a caption string above.
- (when (and caption org-e-ascii-caption-above) (concat caption "\n"))
- ;; Insert table. Note: "table.el" tables are left unmodified.
- (cond ((eq (org-element-property :type table) 'org) contents)
- ((and org-e-ascii-table-use-ascii-art
- (eq (plist-get info :ascii-charset) 'utf-8)
- (require 'ascii-art-to-unicode nil t))
- (with-temp-buffer
- (insert (org-remove-indentation
- (org-element-property :value table)))
- (goto-char (point-min))
- (aa2u)
- (goto-char (point-max))
- (skip-chars-backward " \r\t\n")
- (buffer-substring (point-min) (point))))
- (t (org-remove-indentation (org-element-property :value table))))
- ;; Possible add a caption string below.
- (when (and caption (not org-e-ascii-caption-above))
- (concat "\n" caption)))))
-
-
-;;;; Table Cell
-
-(defun org-e-ascii--table-cell-width (table-cell info)
- "Return width of TABLE-CELL.
-
-INFO is a plist used as a communication channel.
-
-Width of a cell is determined either by a width cookie in the
-same column as the cell, or by the maximum cell's length in that
-column.
-
-When `org-e-ascii-table-widen-columns' is non-nil, width cookies
-are ignored."
- (or (and (not org-e-ascii-table-widen-columns)
- (org-export-table-cell-width table-cell info))
- (let* ((max-width 0)
- (table (org-export-get-parent-table table-cell))
- (specialp (org-export-table-has-special-column-p table))
- (col (cdr (org-export-table-cell-address table-cell info))))
- (org-element-map
- table 'table-row
- (lambda (row)
- (setq max-width
- (max (length
- (org-export-data
- (org-element-contents
- (elt (if specialp (cdr (org-element-contents row))
- (org-element-contents row))
- col))
- info))
- max-width)))
- info)
- max-width)))
-
-(defun org-e-ascii-table-cell (table-cell contents info)
- "Transcode a TABLE-CELL object from Org to ASCII.
-CONTENTS is the cell contents. INFO is a plist used as
-a communication channel."
- ;; Determine column width. When `org-e-ascii-table-widen-columns'
- ;; is nil and some width cookie has set it, use that value.
- ;; Otherwise, compute the maximum width among transcoded data of
- ;; each cell in the column.
- (let ((width (org-e-ascii--table-cell-width table-cell info)))
- ;; When contents are too large, truncate them.
- (unless (or org-e-ascii-table-widen-columns (<= (length contents) width))
- (setq contents (concat (substring contents 0 (- width 2)) "=>")))
- ;; Align contents correctly within the cell.
- (let* ((indent-tabs-mode nil)
- (data
- (when contents
- (org-e-ascii--justify-string
- contents width
- (org-export-table-cell-alignment table-cell info)))))
- (setq contents (concat data (make-string (- width (length data)) ? ))))
- ;; Return cell.
- (concat (format " %s " contents)
- (when (memq 'right (org-export-table-cell-borders table-cell info))
- (if (eq (plist-get info :ascii-charset) 'utf-8) "│" "|")))))
-
-
-;;;; Table Row
-
-(defun org-e-ascii-table-row (table-row contents info)
- "Transcode a TABLE-ROW element from Org to ASCII.
-CONTENTS is the row contents. INFO is a plist used as
-a communication channel."
- (when (eq (org-element-property :type table-row) 'standard)
- (let ((build-hline
- (function
- (lambda (lcorner horiz vert rcorner)
- (concat
- (apply
- 'concat
- (org-element-map
- table-row 'table-cell
- (lambda (cell)
- (let ((width (org-e-ascii--table-cell-width cell info))
- (borders (org-export-table-cell-borders cell info)))
- (concat
- ;; In order to know if CELL starts the row, do
- ;; not compare it with the first cell in the row
- ;; as there might be a special column. Instead,
- ;; compare it with the first exportable cell,
- ;; obtained with `org-element-map'.
- (when (and (memq 'left borders)
- (eq (org-element-map
- table-row 'table-cell 'identity info t)
- cell))
- lcorner)
- (make-string (+ 2 width) (string-to-char horiz))
- (cond
- ((not (memq 'right borders)) nil)
- ((eq (car (last (org-element-contents table-row))) cell)
- rcorner)
- (t vert)))))
- info)) "\n"))))
- (utf8p (eq (plist-get info :ascii-charset) 'utf-8))
- (borders (org-export-table-cell-borders
- (org-element-map table-row 'table-cell 'identity info t)
- info)))
- (concat (cond
- ((and (memq 'top borders) (or utf8p (memq 'above borders)))
- (if utf8p (funcall build-hline "┍" "━" "┯" "┑")
- (funcall build-hline "+" "-" "+" "+")))
- ((memq 'above borders)
- (if utf8p (funcall build-hline "├" "─" "┼" "┤")
- (funcall build-hline "+" "-" "+" "+"))))
- (when (memq 'left borders) (if utf8p "│" "|"))
- contents "\n"
- (when (and (memq 'bottom borders) (or utf8p (memq 'below borders)))
- (if utf8p (funcall build-hline "┕" "━" "┷" "┙")
- (funcall build-hline "+" "-" "+" "+")))))))
-
-
-;;;; Target
-
-;; Targets are invisible.
-
-
-;;;; Timestamp
-
-(defun org-e-ascii-timestamp (timestamp contents info)
- "Transcode a TIMESTAMP object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((value (org-translate-time (org-element-property :value timestamp)))
- (range-end
- (org-translate-time (org-element-property :range-end timestamp)))
- (utf8p (eq (plist-get info :ascii-charset) 'utf-8)))
- (concat value
- (when range-end (concat (if utf8p "–" "--") range-end)))))
-
-
-;;;; Underline
-
-(defun org-e-ascii-underline (underline contents info)
- "Transcode UNDERLINE from Org to ASCII.
-CONTENTS is the text with underline markup. INFO is a plist
-holding contextual information."
- (format "_%s_" contents))
-
-
-;;;; Verbatim
-
-(defun org-e-ascii-verbatim (verbatim contents info)
- "Return a VERBATIM object from Org to ASCII.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (format org-e-ascii-verbatim-format
- (org-element-property :value verbatim)))
-
-
-;;;; Verse Block
-
-(defun org-e-ascii-verse-block (verse-block contents info)
- "Transcode a VERSE-BLOCK element from Org to ASCII.
-CONTENTS is verse block contents. INFO is a plist holding
-contextual information."
- (let ((verse-width (org-e-ascii--current-text-width verse-block info)))
- (org-e-ascii--indent-string
- (org-e-ascii--justify-string contents verse-width 'left)
- org-e-ascii-quote-margin)))
-
-
-;;; Filter
-
-(defun org-e-ascii-filter-headline-blank-lines (headline back-end info)
- "Filter controlling number of blank lines after an headline.
-
-HEADLINE is a string representing a transcoded headline.
-BACK-END is symbol specifying back-end used for export. INFO is
-plist containing the communication channel.
-
-This function only applies to `e-ascii' back-end. See
-`org-e-ascii-headline-spacing' for information.
-
-For any other back-end, HEADLINE is returned as-is."
- (if (not org-e-ascii-headline-spacing) headline
- (let ((blanks (make-string (1+ (cdr org-e-ascii-headline-spacing)) ?\n)))
- (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" blanks headline))))
-
-
-
-;;; Interactive function
-
-;;;###autoload
-(defun org-e-ascii-export-as-ascii
- (&optional subtreep visible-only body-only ext-plist)
- "Export current buffer to a text buffer.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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, strip title, table
-of contents and footnote definitions from output.
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-Export is done in a buffer named \"*Org E-ASCII Export*\", which
-will be displayed when `org-export-show-temporary-export-buffer'
-is non-nil."
- (interactive)
- (let ((outbuf (org-export-to-buffer
- 'e-ascii "*Org E-ASCII Export*"
- subtreep visible-only body-only ext-plist)))
- (with-current-buffer outbuf (text-mode))
- (when org-export-show-temporary-export-buffer
- (switch-to-buffer-other-window outbuf))))
-
-;;;###autoload
-(defun org-e-ascii-export-to-ascii
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to a text file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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, strip title, table
-of contents and footnote definitions from output.
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (let ((outfile (org-export-output-file-name ".txt" subtreep pub-dir)))
- (org-export-to-file
- 'e-ascii outfile subtreep visible-only body-only ext-plist)))
-
-
-(provide 'org-e-ascii)
-;;; org-e-ascii.el ends here
diff --git a/contrib/lisp/org-e-beamer.el b/contrib/lisp/org-e-beamer.el
deleted file mode 100644
index 0c3c430..0000000
--- a/contrib/lisp/org-e-beamer.el
+++ /dev/null
@@ -1,1069 +0,0 @@
-;;; org-e-beamer.el --- Beamer Back-End for Org Export Engine
-
-;; Copyright (C) 2007-2012 Free Software Foundation, Inc.
-
-;; Author: Carsten Dominik <carsten.dominik AT gmail DOT com>
-;; Nicolas Goaziou <n.goaziou AT gmail DOT com>
-;; Keywords: org, wp, tex
-
-;; GNU Emacs 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.
-
-;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; This library implements both a Beamer back-end, derived from the
-;; LaTeX one and a minor mode easing structure edition of the
-;; document.
-;;
-;; Depending on the desired output format, three commands are provided
-;; for export: `org-e-beamer-export-as-latex' (temporary buffer),
-;; `org-e-beamer-export-to-latex' ("tex" file) and
-;; `org-e-beamer-export-to-pdf' ("pdf" file).
-;;
-;; On top of buffer keywords supported by `e-latex' back-end (see
-;; `org-e-latex-options-alist'), this back-end introduces the
-;; following keywords: "BEAMER_THEME", "BEAMER_COLOR_THEME",
-;; "BEAMER_FONT_THEME", "BEAMER_INNER_THEME" and "BEAMER_OUTER_THEME".
-;; All accept options in square brackets.
-;;
-;; Moreover, headlines now fall into three categories: sectioning
-;; elements, frames and blocks.
-;;
-;; - Like `e-latex' back-end sectioning elements are still set through
-;; `org-e-latex-classes' variable.
-;;
-;; - Headlines become frames when their level is equal to
-;; `org-e-beamer-frame-level' (or "H" value in the OPTIONS line).
-;; Though, if an headline in the current tree has a "BEAMER_env"
-;; (see below) property set to "frame", its level overrides the
-;; variable.
-;;
-;; - All frames' children become block environments. Special block
-;; types can be enforced by setting headline's "BEAMER_env" property
-;; to an appropriate value (see `org-e-beamer-environments-default'
-;; for supported value and `org-e-beamer-environments-extra' for
-;; adding more).
-;;
-;; - As a special case, if the "BEAMER_env" property is set to either
-;; "appendix", "note" or "noteNH", the headline will become,
-;; respectively, an appendix, a note (within frame or between frame,
-;; depending on its level) and a note with its title ignored.
-;;
-;; Also, an headline with an "ignoreheading" value will have its
-;; contents only inserted in the output. This special value is
-;; useful to have data between frames, or to properly close
-;; a "column" environment.
-;;
-;; Along with "BEAMER_env", headlines also support "BEAMER_act" and
-;; "BEAMER_opt" properties. The former is translated as an
-;; overlay/action specification (or a default overlay specification
-;; when enclosed within square brackets) whereas the latter specifies
-;; options for the current frame ("fragile" option is added
-;; automatically, though).
-;;
-;; Every plain list has support for `:overlay' attribute (through
-;; ATTR_BEAMER affiliated keyword). Also, ordered (resp. description)
-;; lists make use of `:template' (resp. `:long-text') attribute.
-;;
-;; Eventually, an export snippet with a value enclosed within angular
-;; brackets put at the beginning of an element or object whose type is
-;; among `bold', `item', `link', `radio-target' and `target' will
-;; control its overlay specifications.
-;;
-;; On the minor mode side, `org-e-beamer-select-environment' (bound by
-;; default to "C-c C-b") and `org-e-beamer-insert-options-template'
-;; are the two entry points.
-
-;;; Code:
-
-(require 'org-e-latex)
-
-
-
-;;; User-Configurable Variables
-
-(defgroup org-export-e-beamer nil
- "Options specific for using the beamer class in LaTeX export."
- :tag "Org Beamer"
- :group 'org-export
- :version "24.2")
-
-(defcustom org-e-beamer-frame-level 1
- "The level at which headlines become frames.
-
-Headlines at a lower level will be translated into a sectioning
-structure. At a higher level, they will be translated into
-blocks.
-
-If an headline with a \"BEAMER_env\" property set to \"frame\" is
-found within a tree, its level locally overrides this number.
-
-This variable has no effect on headlines with the \"BEAMER_env\"
-property set to either \"ignoreheading\", \"appendix\", or
-\"note\", which will respectively, be invisible, become an
-appendix or a note.
-
-This integer is relative to the minimal level of an headline
-within the parse tree, defined as 1."
- :group 'org-export-e-beamer
- :type 'integer)
-
-(defcustom org-e-beamer-frame-default-options ""
- "Default options string to use for frames.
-For example, it could be set to \"allowframebreaks\"."
- :group 'org-export-e-beamer
- :type '(string :tag "[options]"))
-
-(defcustom org-e-beamer-column-view-format
- "%45ITEM %10BEAMER_env(Env) %10BEAMER_act(Act) %4BEAMER_col(Col) %8BEAMER_opt(Opt)"
- "Column view format that should be used to fill the template."
- :group 'org-export-e-beamer
- :type '(choice
- (const :tag "Do not insert Beamer column view format" nil)
- (string :tag "Beamer column view format")))
-
-(defcustom org-e-beamer-theme "default"
- "Default theme used in Beamer presentations."
- :group 'org-export-e-beamer
- :type '(choice
- (const :tag "Do not insert a Beamer theme" nil)
- (string :tag "Beamer theme")))
-
-(defcustom org-e-beamer-environments-extra nil
- "Environments triggered by tags in Beamer export.
-Each entry has 4 elements:
-
-name Name of the environment
-key Selection key for `org-e-beamer-select-environment'
-open The opening template for the environment, with the following escapes
- %a the action/overlay specification
- %A the default action/overlay specification
- %o the options argument of the template
- %h the headline text
- %H if there is headline text, that text in {} braces
- %U if there is headline text, that text in [] brackets
-close The closing string of the environment."
- :group 'org-export-e-beamer
- :type '(repeat
- (list
- (string :tag "Environment")
- (string :tag "Selection key")
- (string :tag "Begin")
- (string :tag "End"))))
-
-(defcustom org-e-beamer-outline-frame-title "Outline"
- "Default title of a frame containing an outline."
- :group 'org-export-e-beamer
- :type '(string :tag "Outline frame title"))
-
-(defcustom org-e-beamer-outline-frame-options ""
- "Outline frame options appended after \\begin{frame}.
-You might want to put e.g. \"allowframebreaks=0.9\" here."
- :group 'org-export-e-beamer
- :type '(string :tag "Outline frame options"))
-
-
-
-;;; Internal Variables
-
-(defconst org-e-beamer-column-widths
- "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 0.0 :ETC"
-"The column widths that should be installed as allowed property values.")
-
-(defconst org-e-beamer-environments-special
- '(("appendix" "x")
- ("column" "c")
- ("frame" "f")
- ("ignoreheading" "i")
- ("note" "n")
- ("noteNH" "N"))
- "Alist of environments treated in a special way by the back-end.
-Keys are environment names, as strings, values are bindings used
-in `org-e-beamer-select-environment'. Environments listed here,
-along with their binding, are hard coded and cannot be modified
-through `org-e-beamer-environments-extra' variable.")
-
-(defconst org-e-beamer-environments-default
- '(("block" "b" "\\begin{block}%a{%h}" "\\end{block}")
- ("alertblock" "a" "\\begin{alertblock}%a{%h}" "\\end{alertblock}")
- ("verse" "v" "\\begin{verse}%a %% %h" "\\end{verse}")
- ("quotation" "q" "\\begin{quotation}%a %% %h" "\\end{quotation}")
- ("quote" "Q" "\\begin{quote}%a %% %h" "\\end{quote}")
- ("structureenv" "s" "\\begin{structureenv}%a %% %h" "\\end{structureenv}")
- ("theorem" "t" "\\begin{theorem}%a%U" "\\end{theorem}")
- ("definition" "d" "\\begin{definition}%a%U" "\\end{definition}")
- ("example" "e" "\\begin{example}%a%U" "\\end{example}")
- ("exampleblock" "E" "\\begin{exampleblock}%a{%h}" "\\end{exampleblock}")
- ("proof" "p" "\\begin{proof}%a%U" "\\end{proof}")
- ("beamercolorbox" "o" "\\begin{beamercolorbox}%o{%h}" "\\end{beamercolorbox}"))
- "Environments triggered by properties in Beamer export.
-These are the defaults - for user definitions, see
-`org-e-beamer-environments-extra'.")
-
-(defconst org-e-beamer-verbatim-elements
- '(code example-block fixed-width inline-src-block src-block verbatim)
- "List of element or object types producing verbatim text.
-This is used internally to determine when a frame should have the
-\"fragile\" option.")
-
-
-
-;;; Internal functions
-
-(defun org-e-beamer--normalize-argument (argument type)
- "Return ARGUMENT string with proper boundaries.
-
-TYPE is a symbol among the following:
-`action' Return ARGUMENT within angular brackets.
-`defaction' Return ARGUMENT within both square and angular brackets.
-`option' Return ARGUMENT within square brackets."
- (if (not (string-match "\\S-" argument)) ""
- (case type
- (action (if (string-match "\\`<.*>\\'" argument) argument
- (format "<%s>" argument)))
- (defaction (cond
- ((string-match "\\`\\[<.*>\\]\\'" argument) argument)
- ((string-match "\\`<.*>\\'" argument)
- (format "[%s]" argument))
- ((string-match "\\`\\[\\(.*\\)\\]\\'" argument)
- (format "[<%s>]" (match-string 1 argument)))
- (t (format "[<%s>]" argument))))
- (option (if (string-match "\\`\\[.*\\]\\'" argument) argument
- (format "[%s]" argument)))
- (otherwise argument))))
-
-(defun org-e-beamer--element-has-overlay-p (element)
- "Non-nil when ELEMENT has an overlay specified.
-An element has an overlay specification when it starts with an
-`e-beamer' export-snippet whose value is between angular
-brackets. Return overlay specification, as a string, or nil."
- (let ((first-object (car (org-element-contents element))))
- (when (eq (org-element-type first-object) 'export-snippet)
- (let ((value (org-element-property :value first-object)))
- (and (string-match "\\`<.*>\\'" value) value)))))
-
-
-
-;;; Define Back-End
-
-(org-export-define-derived-backend e-beamer e-latex
- :export-block "BEAMER"
- :options-alist
- ((:beamer-theme "BEAMER_THEME" nil org-e-beamer-theme)
- (:beamer-color-theme "BEAMER_COLOR_THEME" nil nil t)
- (:beamer-font-theme "BEAMER_FONT_THEME" nil nil t)
- (:beamer-inner-theme "BEAMER_INNER_THEME" nil nil t)
- (:beamer-outer-theme "BEAMER_OUTER_THEME" nil nil t)
- (:headline-levels nil "H" org-e-beamer-frame-level))
- :translate-alist ((bold . org-e-beamer-bold)
- (export-block . org-e-beamer-export-block)
- (export-snippet . org-e-beamer-export-snippet)
- (headline . org-e-beamer-headline)
- (item . org-e-beamer-item)
- (keyword . org-e-beamer-keyword)
- (link . org-e-beamer-link)
- (plain-list . org-e-beamer-plain-list)
- (radio-target . org-e-beamer-radio-target)
- (target . org-e-beamer-target)
- (template . org-e-beamer-template)))
-
-
-
-;;; Transcode Functions
-
-;;;; Bold
-
-(defun org-e-beamer-bold (bold contents info)
- "Transcode BLOCK object into Beamer code.
-CONTENTS is the text being bold. INFO is a plist used as
-a communication channel."
- (format "\\alert%s{%s}"
- (or (org-e-beamer--element-has-overlay-p bold) "")
- contents))
-
-
-;;;; Export Block
-
-(defun org-e-beamer-export-block (export-block contents info)
- "Transcode an EXPORT-BLOCK element into Beamer code.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (when (member (org-element-property :type export-block) '("BEAMER" "LATEX"))
- (org-remove-indentation (org-element-property :value export-block))))
-
-
-;;;; Export Snippet
-
-(defun org-e-beamer-export-snippet (export-snippet contents info)
- "Transcode an EXPORT-SNIPPET object into Beamer code.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (let ((backend (org-export-snippet-backend export-snippet))
- (value (org-element-property :value export-snippet)))
- ;; Only "e-latex" and "e-beamer" snippets are retained.
- (cond ((eq backend 'e-latex) value)
- ;; Ignore "e-beamer" snippets specifying overlays.
- ((and (eq backend 'e-beamer)
- (or (org-export-get-previous-element export-snippet info)
- (not (string-match "\\`<.*>\\'" value))))
- value))))
-
-
-;;;; Headline
-;;
-;; The main function to translate an headline is
-;; `org-e-beamer-headline'.
-;;
-;; Depending on the level at which an headline is considered as
-;; a frame (given by `org-e-beamer--frame-level'), the headline is
-;; either a section (`org-e-beamer--format-section'), a frame
-;; (`org-e-beamer--format-frame') or a block
-;; (`org-e-beamer--format-block').
-;;
-;; `org-e-beamer-headline' also takes care of special environments
-;; like "ignoreheading", "note", "noteNH" and "appendix".
-
-(defun org-e-beamer--frame-level (headline info)
- "Return frame level in subtree containing HEADLINE.
-INFO is a plist used as a communication channel."
- (or
- ;; 1. Look for "frame" environment in parents, starting from the
- ;; farthest.
- (catch 'exit
- (mapc (lambda (parent)
- (when (equal (org-element-property :beamer-env parent) "frame")
- (throw 'exit (org-export-get-relative-level parent info))))
- (reverse (org-export-get-genealogy headline)))
- nil)
- ;; 2. Look for "frame" environment in HEADLINE.
- (and (equal (org-element-property :beamer-env headline) "frame")
- (org-export-get-relative-level headline info))
- ;; 3. Look for "frame" environment in sub-tree.
- (org-element-map
- headline 'headline
- (lambda (hl)
- (when (equal (org-element-property :beamer-env hl) "frame")
- (org-export-get-relative-level hl info)))
- info 'first-match)
- ;; 4. No "frame" environment in tree: use default value.
- (plist-get info :headline-levels)))
-
-(defun org-e-beamer--format-section (headline contents info)
- "Format HEADLINE as a sectioning part.
-CONTENTS holds the contents of the headline. INFO is a plist
-used as a communication channel."
- ;; Use `e-latex' back-end output, inserting overlay specifications
- ;; if possible.
- (let ((latex-headline
- (funcall (cdr (assq 'headline org-e-latex-translate-alist))
- headline contents info))
- (mode-specs (org-element-property :beamer-act headline)))
- (if (and mode-specs
- (string-match "\\`\\\\\\(.*?\\)\\(?:\\*\\|\\[.*\\]\\)?{"
- latex-headline))
- (replace-match (concat (match-string 1 latex-headline)
- (format "<%s>" mode-specs))
- nil nil latex-headline 1)
- latex-headline)))
-
-(defun org-e-beamer--format-frame (headline contents info)
- "Format HEADLINE as a frame.
-CONTENTS holds the contents of the headline. INFO is a plist
-used as a communication channel."
- (let ((fragilep
- ;; FRAGILEP is non-nil when HEADLINE contains an element
- ;; among `org-e-beamer-verbatim-elements'.
- (org-element-map headline org-e-beamer-verbatim-elements 'identity
- info 'first-match)))
- (concat "\\begin{frame}"
- ;; Overlay specification, if any. If is surrounded by square
- ;; brackets, consider it as a default specification.
- (let ((action (org-element-property :beamer-act headline)))
- (cond
- ((not action) "")
- ((string-match "\\`\\[.*\\]\\'" action )
- (org-e-beamer--normalize-argument action 'defaction))
- (t (org-e-beamer--normalize-argument action 'action))))
- ;; Options, if any.
- (let ((options
- ;; Collect options from default value and headline's
- ;; properties. Also add a label for links.
- (append
- (org-split-string org-e-beamer-frame-default-options
- ",")
- (let ((opt (org-element-property :beamer-opt headline)))
- (and opt (org-split-string
- ;; Remove square brackets if user
- ;; provided them.
- (and (string-match "^\\[?\\(.*\\)\\]?$" opt)
- (match-string 1 opt))
- ",")))
- (list
- (format "label=sec-%s"
- (mapconcat
- 'number-to-string
- (org-export-get-headline-number headline info)
- "-"))))))
- ;; Change options list into a string.
- (org-e-beamer--normalize-argument
- (mapconcat
- 'identity
- (if (or (not fragilep) (member "fragile" options)) options
- (cons "fragile" options))
- ",")
- 'option))
- ;; Title.
- (format "{%s}"
- (org-export-data (org-element-property :title headline)
- info))
- "\n"
- ;; The following workaround is required in fragile frames
- ;; as Beamer will append "\par" to the beginning of the
- ;; contents. So we need to make sure the command is
- ;; separated from the contents by at least one space. If
- ;; it isn't, it will create "\parfirst-word" command and
- ;; remove the first word from the contents in the PDF
- ;; output.
- (if (not fragilep) contents
- (replace-regexp-in-string "\\`\n*" "\\& " contents))
- "\\end{frame}")))
-
-(defun org-e-beamer--format-block (headline contents info)
- "Format HEADLINE as a block.
-CONTENTS holds the contents of the headline. INFO is a plist
-used as a communication channel."
- (let* ((column-width (org-element-property :beamer-col headline))
- ;; Environment defaults to "block" if none is specified and
- ;; there is no column specification. If there is a column
- ;; specified but still no explicit environment, ENVIRONMENT
- ;; is nil.
- (environment (let ((env (org-element-property :beamer-env headline)))
- (cond
- ;; "block" is the fallback environment.
- ((and (not env) (not column-width)) "block")
- ;; "column" only.
- ((not env) nil)
- ;; Use specified environment.
- (t (downcase env)))))
- (env-format (when environment
- (assoc environment
- (append org-e-beamer-environments-special
- org-e-beamer-environments-extra
- org-e-beamer-environments-default))))
- (title (org-export-data (org-element-property :title headline) info))
- ;; Start a columns environment when there is no previous
- ;; headline or the previous headline do not have
- ;; a BEAMER_column property.
- (start-columns-p
- (and column-width
- (or (org-export-first-sibling-p headline info)
- (not (org-element-property
- :beamer-col
- (org-export-get-previous-element headline info))))))
- ;; Ends a columns environment when there is no next headline
- ;; or the next headline do not have a BEAMER_column property.
- (end-columns-p
- (and column-width
- (or (org-export-last-sibling-p headline info)
- (not (org-element-property
- :beamer-col
- (org-export-get-next-element headline info)))))))
- (concat
- (when start-columns-p "\\begin{columns}\n")
- (when column-width
- (format "\\begin{column}%s{%s}\n"
- ;; One can specify placement for column only when
- ;; HEADLINE stands for a column on its own.
- (if (not environment) ""
- (let ((options (org-element-property :beamer-opt headline)))
- (if (not options) ""
- (org-e-beamer--normalize-argument options 'option))))
- (format "%s\\textwidth" column-width)))
- ;; Block's opening string.
- (when env-format
- (concat
- (org-fill-template
- (nth 2 env-format)
- (nconc
- ;; If BEAMER_act property has its value enclosed in square
- ;; brackets, it is a default overlay specification and
- ;; overlay specification is empty. Otherwise, it is an
- ;; overlay specification and the default one is nil.
- (let ((action (org-element-property :beamer-act headline)))
- (cond
- ((not action) (list (cons "a" "") (cons "A" "")))
- ((string-match "\\`\\[.*\\]\\'" action)
- (list
- (cons "A"
- (org-e-beamer--normalize-argument action 'defaction))
- (cons "a" "")))
- (t
- (list
- (cons "a"
- (org-e-beamer--normalize-argument action 'action))
- (cons "A" "")))))
- (list (cons "o"
- (let ((options
- (org-element-property :beamer-opt headline)))
- (if (not options) ""
- (org-e-beamer--normalize-argument options 'option))))
- (cons "h" title)
- (cons "H" (if (equal title "") "" (format "{%s}" title)))
- (cons "U" (if (equal title "") "" (format "[%s]" title))))))
- "\n"))
- contents
- ;; Block's closing string.
- (when environment (concat (nth 3 env-format) "\n"))
- (when column-width "\\end{column}\n")
- (when end-columns-p "\\end{columns}"))))
-
-(defun org-e-beamer-headline (headline contents info)
- "Transcode HEADLINE element into Beamer code.
-CONTENTS is the contents of the headline. INFO is a plist used
-as a communication channel."
- (unless (org-element-property :footnote-section-p headline)
- (let ((level (org-export-get-relative-level headline info))
- (frame-level (org-e-beamer--frame-level headline info))
- (environment (let ((env (org-element-property :beamer-env headline)))
- (if (stringp env) (downcase env) "block"))))
- (cond
- ;; Creation of an appendix is requested.
- ((equal environment "appendix")
- (concat "\\appendix"
- (org-element-property :beamer-act headline)
- "\n"
- (make-string (org-element-property :pre-blank headline) ?\n)
- contents))
- ((equal environment "ignoreheading")
- (concat (make-string (org-element-property :pre-blank headline) ?\n)
- contents))
- ;; HEADLINE is a note.
- ((member environment '("note" "noteNH"))
- (format "\\note{%s}"
- (concat (and (equal environment "note")
- (concat
- (org-export-data
- (org-element-property :title headline) info)
- "\n"))
- (org-trim contents))))
- ;; HEADLINE is a frame.
- ((or (equal environment "frame") (= level frame-level))
- (org-e-beamer--format-frame headline contents info))
- ;; Regular section, extracted from `org-e-latex-classes'.
- ((< level frame-level)
- (org-e-beamer--format-section headline contents info))
- ;; Otherwise, HEADLINE is a block.
- (t (org-e-beamer--format-block headline contents info))))))
-
-
-;;;; Item
-
-(defun org-e-beamer-item (item contents info)
- "Transcode an ITEM element into Beamer code.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let ((action (let ((first-element (car (org-element-contents item))))
- (and (eq (org-element-type first-element) 'paragraph)
- (org-e-beamer--element-has-overlay-p first-element))))
- (output (funcall (cdr (assq 'item org-e-latex-translate-alist))
- item contents info)))
- (if (not action) output
- ;; If the item starts with a paragraph and that paragraph starts
- ;; with an export snippet specifying an overlay, insert it after
- ;; \item command.
- (replace-regexp-in-string "\\\\item" (concat "\\\\item" action) output))))
-
-
-;;;; Keyword
-
-(defun org-e-beamer-keyword (keyword contents info)
- "Transcode a KEYWORD element into Beamer code.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (let ((key (org-element-property :key keyword))
- (value (org-element-property :value keyword)))
- ;; Handle specifically BEAMER and TOC (headlines only) keywords.
- ;; Otherwise, fallback to `e-latex' back-end.
- (cond
- ((equal key "BEAMER") value)
- ((and (equal key "TOC") (string-match "\\<headlines\\>" value))
- (let ((depth (or (and (string-match "[0-9]+" value)
- (string-to-number (match-string 0 value)))
- (plist-get info :with-toc)))
- (options (and (string-match "\\[.*?\\]" value)
- (match-string 0 value))))
- (concat
- "\\begin{frame}"
- (when (wholenump depth) (format "\\setcounter{tocdepth}{%s}\n" depth))
- "\\tableofcontents" options "\n"
- "\\end{frame}")))
- (t (funcall (cdr (assq 'keyword org-e-latex-translate-alist))
- keyword contents info)))))
-
-
-;;;; Link
-
-(defun org-e-beamer-link (link contents info)
- "Transcode a LINK object into Beamer code.
-CONTENTS is the description part of the link. INFO is a plist
-used as a communication channel."
- (let ((type (org-element-property :type link))
- (path (org-element-property :path link)))
- ;; Use \hyperlink command for all internal links.
- (cond
- ((equal type "radio")
- (let ((destination (org-export-resolve-radio-link link info)))
- (when destination
- (format "\\hyperlink%s{%s}{%s}"
- (or (org-e-beamer--element-has-overlay-p link) "")
- (org-export-solidify-link-text path)
- (org-export-data (org-element-contents destination) info)))))
- ((and (member type '("custom-id" "fuzzy" "id"))
- (let ((destination (if (string= type "fuzzy")
- (org-export-resolve-fuzzy-link link info)
- (org-export-resolve-id-link link info))))
- (case (org-element-type destination)
- (headline
- (let ((label
- (format "sec-%s"
- (mapconcat
- 'number-to-string
- (org-export-get-headline-number
- destination info)
- "-"))))
- (if (and (plist-get info :section-numbers) (not contents))
- (format "\\ref{%s}" label)
- (format "\\hyperlink%s{%s}{%s}"
- (or (org-e-beamer--element-has-overlay-p link) "")
- label
- contents))))
- (target
- (let ((path (org-export-solidify-link-text path)))
- (if (not contents) (format "\\ref{%s}" path)
- (format "\\hyperlink%s{%s}{%s}"
- (or (org-e-beamer--element-has-overlay-p link) "")
- path
- contents))))))))
- ;; Otherwise, use `e-latex' back-end.
- (t (funcall (cdr (assq 'link org-e-latex-translate-alist))
- link contents info)))))
-
-
-;;;; Plain List
-;;
-;; Plain lists support `:overlay' (for any type), `:template' (for
-;; ordered lists only) and `:long-text' (for description lists only)
-;; attributes.
-
-(defun org-e-beamer-plain-list (plain-list contents info)
- "Transcode a PLAIN-LIST element into Beamer code.
-CONTENTS is the contents of the list. INFO is a plist holding
-contextual information."
- (let* ((type (org-element-property :type plain-list))
- (attributes (org-export-read-attribute :attr_beamer plain-list))
- (latex-type (cond ((eq type 'ordered) "enumerate")
- ((eq type 'descriptive) "description")
- (t "itemize"))))
- (org-e-latex--wrap-label
- plain-list
- (format "\\begin{%s}%s%s\n%s\\end{%s}"
- latex-type
- ;; Default overlay specification, if any.
- (let ((overlay (plist-get attributes :overlay)))
- (if (not overlay) ""
- (org-e-beamer--normalize-argument overlay 'defaction)))
- ;; Second optional argument depends on the list type.
- (case type
- (ordered
- (let ((template (plist-get attributes :template)))
- (if (not template) ""
- (org-e-beamer--normalize-argument template 'option))))
- (descriptive
- (let ((long-text (plist-get attributes :long-text)))
- (if (not long-text) ""
- (org-e-beamer--normalize-argument long-text 'option))))
- ;; There's no second argument for un-ordered lists.
- (otherwise ""))
- ;; Eventually insert contents and close environment.
- contents
- latex-type))))
-
-
-;;;; Radio Target
-
-(defun org-e-beamer-radio-target (radio-target text info)
- "Transcode a RADIO-TARGET object into Beamer code.
-TEXT is the text of the target. INFO is a plist holding
-contextual information."
- (format "\\hypertarget%s{%s}{%s}"
- (or (org-e-beamer--element-has-overlay-p radio-target) "")
- (org-export-solidify-link-text
- (org-element-property :value radio-target))
- text))
-
-
-;;;; Target
-
-(defun org-e-beamer-target (target contents info)
- "Transcode a TARGET object into Beamer code.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format "\\hypertarget{%s}{}"
- (org-export-solidify-link-text (org-element-property :value target))))
-
-
-;;;; Template
-;;
-;; Template used is similar to the one used in `e-latex' back-end,
-;; excepted for the table of contents and Beamer themes.
-
-(defun org-e-beamer-template (contents info)
- "Return complete document string after Beamer conversion.
-CONTENTS is the transcoded contents string. INFO is a plist
-holding export options."
- (let ((title (org-export-data (plist-get info :title) info)))
- (concat
- ;; 1. Time-stamp.
- (and (plist-get info :time-stamp-file)
- (format-time-string "%% Created %Y-%m-%d %a %H:%M\n"))
- ;; 2. Document class and packages.
- (let ((class (plist-get info :latex-class))
- (class-options (plist-get info :latex-class-options)))
- (org-element-normalize-string
- (let* ((header (nth 1 (assoc class org-e-latex-classes)))
- (document-class-string
- (and (stringp header)
- (if class-options
- (replace-regexp-in-string
- "^[ \t]*\\\\documentclass\\(\\[.*?\\]\\)"
- class-options header t nil 1)
- header))))
- (when document-class-string
- (org-e-latex--guess-babel-language
- (org-e-latex--guess-inputenc
- (org-splice-latex-header
- document-class-string
- org-export-latex-default-packages-alist ; defined in org.el
- org-export-latex-packages-alist nil ; defined in org.el
- (plist-get info :latex-header-extra)))
- info)))))
- ;; 3. Insert themes.
- (let ((format-theme
- (function
- (lambda (prop command)
- (let ((theme (plist-get info prop)))
- (when theme
- (concat command
- (if (not (string-match "\\[.*\\]" theme))
- (format "{%s}\n" theme)
- (format "%s{%s}\n"
- (match-string 0 theme)
- (org-trim
- (replace-match "" nil nil theme)))))))))))
- (mapconcat (lambda (args) (apply format-theme args))
- '((:beamer-theme "\\usetheme")
- (:beamer-color-theme "\\usecolortheme")
- (:beamer-font-theme "\\usefonttheme")
- (:beamer-inner-theme "\\useinnertheme")
- (:beamer-outer-theme "\\useoutertheme"))
- ""))
- ;; 4. Possibly limit depth for headline numbering.
- (let ((sec-num (plist-get info :section-numbers)))
- (when (integerp sec-num)
- (format "\\setcounter{secnumdepth}{%d}\n" sec-num)))
- ;; 5. Author.
- (let ((author (and (plist-get info :with-author)
- (let ((auth (plist-get info :author)))
- (and auth (org-export-data auth info)))))
- (email (and (plist-get info :with-email)
- (org-export-data (plist-get info :email) info))))
- (cond ((and author email (not (string= "" email)))
- (format "\\author{%s\\thanks{%s}}\n" author email))
- (author (format "\\author{%s}\n" author))
- (t "\\author{}\n")))
- ;; 6. Date.
- (format "\\date{%s}\n" (org-export-data (plist-get info :date) info))
- ;; 7. Title
- (format "\\title{%s}\n" title)
- ;; 8. Hyperref options.
- (format "\\hypersetup{\n pdfkeywords={%s},\n pdfsubject={%s},\n pdfcreator={%s}}\n"
- (or (plist-get info :keywords) "")
- (or (plist-get info :description) "")
- (if (not (plist-get info :with-creator)) ""
- (plist-get info :creator)))
- ;; 9. Document start.
- "\\begin{document}\n\n"
- ;; 10. Title command.
- (org-element-normalize-string
- (cond ((string= "" title) nil)
- ((not (stringp org-e-latex-title-command)) nil)
- ((string-match "\\(?:[^%]\\|^\\)%s"
- org-e-latex-title-command)
- (format org-e-latex-title-command title))
- (t org-e-latex-title-command)))
- ;; 11. Table of contents.
- (let ((depth (plist-get info :with-toc)))
- (when depth
- (concat
- (format "\\begin{frame}%s{%s}\n"
- (org-e-beamer--normalize-argument
- org-e-beamer-outline-frame-options 'option)
- org-e-beamer-outline-frame-title)
- (when (wholenump depth)
- (format "\\setcounter{tocdepth}{%d}\n" depth))
- "\\tableofcontents\n"
- "\\end{frame}\n\n")))
- ;; 12. Document's body.
- contents
- ;; 13. Creator.
- (let ((creator-info (plist-get info :with-creator)))
- (cond
- ((not creator-info) "")
- ((eq creator-info 'comment)
- (format "%% %s\n" (plist-get info :creator)))
- (t (concat (plist-get info :creator) "\n"))))
- ;; 14. Document end.
- "\\end{document}")))
-
-
-
-;;; Minor Mode
-
-
-(defvar org-e-beamer-mode-map (make-sparse-keymap)
- "The keymap for `org-e-beamer-mode'.")
-(define-key org-e-beamer-mode-map "\C-c\C-b" 'org-e-beamer-select-environment)
-
-;;;###autoload
-(define-minor-mode org-e-beamer-mode
- "Support for editing Beamer oriented Org mode files."
- nil " Bm" 'org-e-beamer-mode-map)
-
-(when (fboundp 'font-lock-add-keywords)
- (font-lock-add-keywords
- 'org-mode
- '((":\\(B_[a-z]+\\|BMCOL\\):" 1 'org-e-beamer-tag prepend))
- 'prepend))
-
-(defface org-e-beamer-tag '((t (:box (:line-width 1 :color grey40))))
- "The special face for beamer tags."
- :group 'org-export-e-beamer)
-
-(defun org-e-beamer-property-changed (property value)
- "Track the BEAMER_env property with tags.
-PROPERTY is the name of the modified property. VALUE is its new
-value."
- (cond
- ((equal property "BEAMER_env")
- (save-excursion
- (org-back-to-heading t)
- (let ((tags (org-get-tags)))
- (setq tags (delq nil (mapcar (lambda (x)
- (if (string-match "^B_" x) nil x))
- tags)))
- (org-set-tags-to tags))
- (when (org-string-nw-p value) (org-toggle-tag (concat "B_" value) 'on))))
- ((equal property "BEAMER_col")
- (org-toggle-tag "BMCOL" (if (org-string-nw-p value) 'on 'off)))))
-
-(add-hook 'org-property-changed-functions 'org-e-beamer-property-changed)
-
-(defun org-e-beamer-allowed-property-values (property)
- "Supply allowed values for PROPERTY."
- (cond
- ((and (equal property "BEAMER_env")
- (not (org-entry-get nil (concat property "_ALL") 'inherit)))
- ;; If no allowed values for BEAMER_env have been defined,
- ;; supply all defined environments
- (mapcar 'car (append org-e-beamer-environments-special
- org-e-beamer-environments-extra
- org-e-beamer-environments-default)))
- ((and (equal property "BEAMER_col")
- (not (org-entry-get nil (concat property "_ALL") 'inherit)))
- ;; If no allowed values for BEAMER_col have been defined,
- ;; supply some
- (org-split-string org-e-beamer-column-widths " "))))
-
-(add-hook 'org-property-allowed-value-functions
- 'org-e-beamer-allowed-property-values)
-
-
-
-;;; Commands
-
-;;;###autoload
-(defun org-e-beamer-export-as-latex
- (&optional subtreep visible-only body-only ext-plist)
- "Export current buffer as a Beamer buffer.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-Export is done in a buffer named \"*Org E-BEAMER Export*\", which
-will be displayed when `org-export-show-temporary-export-buffer'
-is non-nil."
- (interactive)
- (let ((outbuf (org-export-to-buffer
- 'e-beamer "*Org E-BEAMER Export*"
- subtreep visible-only body-only ext-plist)))
- (with-current-buffer outbuf (LaTeX-mode))
- (when org-export-show-temporary-export-buffer
- (switch-to-buffer-other-window outbuf))))
-
-;;;###autoload
-(defun org-e-beamer-export-to-latex
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer as a Beamer presentation (tex).
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (let ((outfile (org-export-output-file-name ".tex" subtreep pub-dir)))
- (org-export-to-file
- 'e-beamer outfile subtreep visible-only body-only ext-plist)))
-
-;;;###autoload
-(defun org-e-beamer-export-to-pdf
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer as a Beamer presentation (PDF).
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return PDF file's name."
- (interactive)
- (org-e-latex-compile
- (org-e-beamer-export-to-latex
- subtreep visible-only body-only ext-plist pub-dir)))
-
-;;;###autoload
-(defun org-e-beamer-select-environment ()
- "Select the environment to be used by beamer for this entry.
-While this uses (for convenience) a tag selection interface, the
-result of this command will be that the BEAMER_env *property* of
-the entry is set.
-
-In addition to this, the command will also set a tag as a visual
-aid, but the tag does not have any semantic meaning."
- (interactive)
- ;; Make sure `org-e-beamer-environments-special' has a higher
- ;; priority than `org-e-beamer-environments-extra'.
- (let* ((envs (append org-e-beamer-environments-special
- org-e-beamer-environments-extra
- org-e-beamer-environments-default))
- (org-tag-alist
- (append '((:startgroup))
- (mapcar (lambda (e) (cons (concat "B_" (car e))
- (string-to-char (nth 1 e))))
- envs)
- '((:endgroup))
- '(("BMCOL" . ?|))))
- (org-fast-tag-selection-single-key t))
- (org-set-tags)
- (let ((tags (or (ignore-errors (org-get-tags-string)) "")))
- (cond
- ((eq org-last-tag-selection-key ?|)
- (if (string-match ":BMCOL:" tags)
- (org-set-property "BEAMER_col" (read-string "Column width: "))
- (org-delete-property "BEAMER_col")))
- ((string-match (concat ":B_\\("
- (mapconcat 'car envs "\\|")
- "\\):")
- tags)
- (org-entry-put nil "BEAMER_env" (match-string 1 tags)))
- (t (org-entry-delete nil "BEAMER_env"))))))
-
-;;;###autoload
-(defun org-e-beamer-insert-options-template (&optional kind)
- "Insert a settings template, to make sure users do this right."
- (interactive (progn
- (message "Current [s]ubtree or [g]lobal?")
- (if (eq (read-char-exclusive) ?g) (list 'global)
- (list 'subtree))))
- (if (eq kind 'subtree)
- (progn
- (org-back-to-heading t)
- (org-reveal)
- (org-entry-put nil "EXPORT_LaTeX_CLASS" "beamer")
- (org-entry-put nil "EXPORT_LaTeX_CLASS_OPTIONS" "[presentation]")
- (org-entry-put nil "EXPORT_FILE_NAME" "presentation.pdf")
- (when org-e-beamer-column-view-format
- (org-entry-put nil "COLUMNS" org-e-beamer-column-view-format))
- (org-entry-put nil "BEAMER_col_ALL" org-e-beamer-column-widths))
- (insert "#+LaTeX_CLASS: beamer\n")
- (insert "#+LaTeX_CLASS_OPTIONS: [presentation]\n")
- (when org-e-beamer-theme
- (insert "#+BEAMER_THEME: " org-e-beamer-theme "\n"))
- (when org-e-beamer-column-view-format
- (insert "#+COLUMNS: " org-e-beamer-column-view-format "\n"))
- (insert "#+PROPERTY: BEAMER_col_ALL " org-e-beamer-column-widths "\n")))
-
-
-(provide 'org-e-beamer)
-;;; org-e-beamer.el ends here
diff --git a/contrib/lisp/org-e-html.el b/contrib/lisp/org-e-html.el
deleted file mode 100644
index f0ba5f9..0000000
--- a/contrib/lisp/org-e-html.el
+++ /dev/null
@@ -1,3044 +0,0 @@
-;;; org-e-html.el --- HTML Back-End For Org Export Engine
-
-;; Copyright (C) 2011-2012 Free Software Foundation, Inc.
-
-;; Author: Jambunathan K <kjambunathan at gmail dot com>
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This library implements a HTML back-end for Org generic exporter.
-
-;; To test it, run
-;;
-;; M-: (org-export-to-buffer 'e-html "*Test e-HTML*") RET
-;;
-;; in an org-mode buffer then switch to the buffer to see the HTML
-;; export. See contrib/lisp/org-export.el for more details on how
-;; this exporter works.
-
-;;; Code:
-
-;;; org-e-html.el
-;;; Dependencies
-
-(require 'org-export)
-(require 'format-spec)
-(eval-when-compile (require 'cl) (require 'table))
-
-
-
-;;; Function Declarations
-
-(declare-function org-id-find-id-file "org-id" (id))
-(declare-function htmlize-region "ext:htmlize" (beg end))
-(declare-function org-pop-to-buffer-same-window
- "org-compat" (&optional buffer-or-name norecord label))
-
-
-;;; Define Back-End
-
-(org-export-define-backend e-html
- ((bold . org-e-html-bold)
- (center-block . org-e-html-center-block)
- (clock . org-e-html-clock)
- (code . org-e-html-code)
- (drawer . org-e-html-drawer)
- (dynamic-block . org-e-html-dynamic-block)
- (entity . org-e-html-entity)
- (example-block . org-e-html-example-block)
- (export-block . org-e-html-export-block)
- (export-snippet . org-e-html-export-snippet)
- (fixed-width . org-e-html-fixed-width)
- (footnote-definition . org-e-html-footnote-definition)
- (footnote-reference . org-e-html-footnote-reference)
- (headline . org-e-html-headline)
- (horizontal-rule . org-e-html-horizontal-rule)
- (inline-src-block . org-e-html-inline-src-block)
- (inlinetask . org-e-html-inlinetask)
- (italic . org-e-html-italic)
- (item . org-e-html-item)
- (keyword . org-e-html-keyword)
- (latex-environment . org-e-html-latex-environment)
- (latex-fragment . org-e-html-latex-fragment)
- (line-break . org-e-html-line-break)
- (link . org-e-html-link)
- (macro . org-e-html-macro)
- (paragraph . org-e-html-paragraph)
- (plain-list . org-e-html-plain-list)
- (plain-text . org-e-html-plain-text)
- (planning . org-e-html-planning)
- (property-drawer . org-e-html-property-drawer)
- (quote-block . org-e-html-quote-block)
- (quote-section . org-e-html-quote-section)
- (radio-target . org-e-html-radio-target)
- (section . org-e-html-section)
- (special-block . org-e-html-special-block)
- (src-block . org-e-html-src-block)
- (statistics-cookie . org-e-html-statistics-cookie)
- (strike-through . org-e-html-strike-through)
- (subscript . org-e-html-subscript)
- (superscript . org-e-html-superscript)
- (table . org-e-html-table)
- (table-cell . org-e-html-table-cell)
- (table-row . org-e-html-table-row)
- (target . org-e-html-target)
- (template . org-e-html-template)
- (timestamp . org-e-html-timestamp)
- (underline . org-e-html-underline)
- (verbatim . org-e-html-verbatim)
- (verse-block . org-e-html-verse-block))
- :export-block "HTML"
- :filters-alist ((:filter-final-output . org-e-html-final-function))
- :options-alist
- ;; FIXME: Prefix KEYWORD and OPTION with "HTML_". Prefix
- ;; corresponding properties with `:html-". If such a renaming is
- ;; taken up, some changes will be required in `org-jsinfo.el',
- ;; I think. So defer renaming for now.
- ((:agenda-style nil nil org-agenda-export-html-style)
- (:creator "CREATOR" nil org-e-html-creator-string)
- (:convert-org-links nil nil org-e-html-link-org-files-as-html)
- ;; (:expand-quoted-html nil "@" org-e-html-expand)
- (:inline-images nil nil org-e-html-inline-images)
- (:link-home "LINK_HOME" nil org-e-html-link-home)
- (:link-up "LINK_UP" nil org-e-html-link-up)
- (:style nil nil org-e-html-style)
- (:style-extra "STYLE" nil org-e-html-style-extra newline)
- (:style-include-default nil nil org-e-html-style-include-default)
- (:style-include-scripts nil nil org-e-html-style-include-scripts)
- ;; (:timestamp nil nil org-e-html-with-timestamp)
- (:html-extension nil nil org-e-html-extension)
- (:html-postamble nil nil org-e-html-postamble)
- (:html-preamble nil nil org-e-html-preamble)
- (:html-table-tag nil nil org-e-html-table-tag)
- (:xml-declaration nil nil org-e-html-xml-declaration)
- (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments)
- (:mathjax "MATHJAX" nil "" space)))
-
-
-
-;;; Internal Variables
-
-;; FIXME: it already exists in org-e-html.el
-(defconst org-e-html-cvt-link-fn
- nil
- "Function to convert link URLs to exportable URLs.
-Takes two arguments, TYPE and PATH.
-Returns exportable url as (TYPE PATH), or nil to signal that it
-didn't handle this case.
-Intended to be locally bound around a call to `org-export-as-html'." )
-
-(defvar org-e-html-format-table-no-css)
-(defvar htmlize-buffer-places) ; from htmlize.el
-(defvar body-only) ; dynamically scoped into this.
-
-(defconst org-e-html-special-string-regexps
- '(("\\\\-" . "&shy;")
- ("---\\([^-]\\)" . "&mdash;\\1")
- ("--\\([^-]\\)" . "&ndash;\\1")
- ("\\.\\.\\." . "&hellip;"))
- "Regular expressions for special string conversion.")
-
-
-(defconst org-e-html-scripts
-"<script type=\"text/javascript\">
-<!--/*--><![CDATA[/*><!--*/
- function CodeHighlightOn(elem, id)
- {
- var target = document.getElementById(id);
- if(null != target) {
- elem.cacheClassElem = elem.className;
- elem.cacheClassTarget = target.className;
- target.className = \"code-highlighted\";
- elem.className = \"code-highlighted\";
- }
- }
- function CodeHighlightOff(elem, id)
- {
- var target = document.getElementById(id);
- if(elem.cacheClassElem)
- elem.className = elem.cacheClassElem;
- if(elem.cacheClassTarget)
- target.className = elem.cacheClassTarget;
- }
-/*]]>*///-->
-</script>"
-"Basic JavaScript that is needed by HTML files produced by Org-mode.")
-
-
-(defconst org-e-html-style-default
-"<style type=\"text/css\">
- <!--/*--><![CDATA[/*><!--*/
- html { font-family: Times, serif; font-size: 12pt; }
- .title { text-align: center; }
- .todo { color: red; }
- .done { color: green; }
- .tag { background-color: #add8e6; font-weight:normal }
- .target { }
- .timestamp { color: #bebebe; }
- .timestamp-kwd { color: #5f9ea0; }
- .right {margin-left:auto; margin-right:0px; text-align:right;}
- .left {margin-left:0px; margin-right:auto; text-align:left;}
- .center {margin-left:auto; margin-right:auto; text-align:center;}
- p.verse { margin-left: 3% }
- pre {
- border: 1pt solid #AEBDCC;
- background-color: #F3F5F7;
- padding: 5pt;
- font-family: courier, monospace;
- font-size: 90%;
- overflow:auto;
- }
- table { border-collapse: collapse; }
- td, th { vertical-align: top; }
- th.right { text-align:center; }
- th.left { text-align:center; }
- th.center { text-align:center; }
- td.right { text-align:right; }
- td.left { text-align:left; }
- td.center { text-align:center; }
- dt { font-weight: bold; }
- div.figure { padding: 0.5em; }
- div.figure p { text-align: center; }
- div.inlinetask {
- padding:10px;
- border:2px solid gray;
- margin:10px;
- background: #ffffcc;
- }
- textarea { overflow-x: auto; }
- .linenr { font-size:smaller }
- .code-highlighted {background-color:#ffff00;}
- .org-info-js_info-navigation { border-style:none; }
- #org-info-js_console-label { font-size:10px; font-weight:bold;
- white-space:nowrap; }
- .org-info-js_search-highlight {background-color:#ffff00; color:#000000;
- font-weight:bold; }
- /*]]>*/-->
-</style>"
- "The default style specification for exported HTML files.
-Please use the variables `org-e-html-style' and
-`org-e-html-style-extra' to add to this style. If you wish to not
-have the default style included, customize the variable
-`org-e-html-style-include-default'.")
-
-
-
-(defvar org-e-html-content-div "content"
- "The name of the container DIV that holds all the page contents.
-
-This variable is obsolete since Org version 7.7.
-Please set `org-e-html-divs' instead.")
-
-
-
-;;; User Configuration Variables
-
-(defgroup org-export-e-html nil
- "Options for exporting Org mode files to HTML."
- :tag "Org Export HTML"
- :group 'org-export)
-
-(defgroup org-export-e-htmlize nil
- "Options for processing examples with htmlize.el."
- :tag "Org Export Htmlize"
- :group 'org-export-e-html)
-
-
-;;;; Bold etc
-
-(defcustom org-e-html-text-markup-alist
- '((bold . "<b>%s</b>")
- (code . "<code>%s</code>")
- (italic . "<i>%s</i>")
- (strike-through . "<del>%s</del>")
- (underline . "<span style=\"text-decoration:underline;\">%s</span>")
- (verbatim . "<code>%s</code>"))
- "Alist of HTML expressions to convert text markup
-
-The key must be a symbol among `bold', `code', `italic',
-`strike-through', `underline' and `verbatim'. The value is
-a formatting string to wrap fontified text with.
-
-If no association can be found for a given markup, text will be
-returned as-is."
- :group 'org-export-e-html
- :type '(alist :key-type (symbol :tag "Markup type")
- :value-type (string :tag "Format string"))
- :options '(bold code italic strike-through underline verbatim))
-
-
-;;;; Debugging
-
-(defcustom org-e-html-pretty-output nil
- "Enable this to generate pretty HTML."
- :group 'org-export-e-html
- :type 'boolean)
-
-
-;;;; Drawers
-
-(defcustom org-e-html-format-drawer-function nil
- "Function called to format a drawer in HTML code.
-
-The function must accept two parameters:
- NAME the drawer name, like \"LOGBOOK\"
- CONTENTS the contents of the drawer.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-html-format-drawer-default \(name contents\)
- \"Format a drawer element for HTML export.\"
- contents\)"
- :group 'org-export-e-html
- :type 'function)
-
-
-;;;; Footnotes
-
-(defcustom org-e-html-footnotes-section "<div id=\"footnotes\">
-<h2 class=\"footnotes\">%s: </h2>
-<div id=\"text-footnotes\">
-%s
-</div>
-</div>"
- "Format for the footnotes section.
-Should contain a two instances of %s. The first will be replaced with the
-language-specific word for \"Footnotes\", the second one will be replaced
-by the footnotes themselves."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-footnote-format "<sup>%s</sup>"
- "The format for the footnote reference.
-%s will be replaced by the footnote reference itself."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-footnote-separator "<sup>, </sup>"
- "Text used to separate footnotes."
- :group 'org-export-e-html
- :type 'string)
-
-
-;;;; Headline
-
-(defcustom org-e-html-toplevel-hlevel 2
- "The <H> level for level 1 headings in HTML export.
-This is also important for the classes that will be wrapped around headlines
-and outline structure. If this variable is 1, the top-level headlines will
-be <h1>, and the corresponding classes will be outline-1, section-number-1,
-and outline-text-1. If this is 2, all of these will get a 2 instead.
-The default for this variable is 2, because we use <h1> for formatting the
-document title."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-format-headline-function nil
- "Function to format headline text.
-
-This function will be called with 5 arguments:
-TODO the todo keyword (string or nil).
-TODO-TYPE the type of todo (symbol: `todo', `done', nil)
-PRIORITY the priority of the headline (integer or nil)
-TEXT the main headline text (string).
-TAGS the tags (string or nil).
-
-The function result will be used in the section format string.
-
-As an example, one could set the variable to the following, in
-order to reproduce the default set-up:
-
-\(defun org-e-html-format-headline \(todo todo-type priority text tags)
- \"Default format function for an headline.\"
- \(concat \(when todo
- \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo))
- \(when priority
- \(format \"\\\\framebox{\\\\#%c} \" priority))
- text
- \(when tags (format \"\\\\hfill{}\\\\textsc{%s}\" tags))))"
- :group 'org-export-e-html
- :type 'function)
-
-
-;;;; HTML-specific
-
-(defcustom org-e-html-allow-name-attribute-in-anchors t
- "When nil, do not set \"name\" attribute in anchors.
-By default, anchors are formatted with both \"id\" and \"name\"
-attributes, when appropriate."
- :group 'org-export-e-html
- :type 'boolean)
-
-
-;;;; Inlinetasks
-
-(defcustom org-e-html-format-inlinetask-function nil
- "Function called to format an inlinetask in HTML code.
-
-The function must accept six parameters:
- TODO the todo keyword, as a string
- TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
- PRIORITY the inlinetask priority, as a string
- NAME the inlinetask name, as a string.
- TAGS the inlinetask tags, as a list of strings.
- CONTENTS the contents of the inlinetask, as a string.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-html-format-inlinetask \(todo type priority name tags contents\)
-\"Format an inline task element for HTML export.\"
- \(let \(\(full-title
- \(concat
- \(when todo
- \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo))
- \(when priority (format \"\\\\framebox{\\\\#%c} \" priority))
- title
- \(when tags (format \"\\\\hfill{}\\\\textsc{%s}\" tags)))))
- \(format (concat \"\\\\begin{center}\\n\"
- \"\\\\fbox{\\n\"
- \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
- \"%s\\n\\n\"
- \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
- \"%s\"
- \"\\\\end{minipage}}\"
- \"\\\\end{center}\")
- full-title contents))"
- :group 'org-export-e-html
- :type 'function)
-
-
-;;;; Links :: Generic
-
-(defcustom org-e-html-link-org-files-as-html t
- "Non-nil means make file links to `file.org' point to `file.html'.
-When org-mode is exporting an org-mode file to HTML, links to
-non-html files are directly put into a href tag in HTML.
-However, links to other Org-mode files (recognized by the
-extension `.org.) should become links to the corresponding html
-file, assuming that the linked org-mode file will also be
-converted to HTML.
-When nil, the links still point to the plain `.org' file."
- :group 'org-export-e-html
- :type 'boolean)
-
-
-;;;; Links :: Inline images
-
-(defcustom org-e-html-inline-images 'maybe
- "Non-nil means inline images into exported HTML pages.
-This is done using an <img> tag. When nil, an anchor with href is used to
-link to the image. If this option is `maybe', then images in links with
-an empty description will be inlined, while images with a description will
-be linked only."
- :group 'org-export-e-html
- :type '(choice (const :tag "Never" nil)
- (const :tag "Always" t)
- (const :tag "When there is no description" maybe)))
-
-(defcustom org-e-html-inline-image-rules
- '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
- ("http" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'")
- ("https" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\|svg\\)\\'"))
- "Rules characterizing image files that can be inlined into HTML.
-
-A rule consists in an association whose key is the type of link
-to consider, and value is a regexp that will be matched against
-link's path.
-
-Note that, by default, the image extension *actually* allowed
-depend on the way the HTML file is processed. When used with
-pdflatex, pdf, jpg and png images are OK. When processing
-through dvi to Postscript, only ps and eps are allowed. The
-default we use here encompasses both."
- :group 'org-export-e-html
- :type '(alist :key-type (string :tag "Type")
- :value-type (regexp :tag "Path")))
-
-
-;;;; Plain Text
-
-(defcustom org-e-html-protect-char-alist
- '(("&" . "&amp;")
- ("<" . "&lt;")
- (">" . "&gt;"))
- "Alist of characters to be converted by `org-e-html-protect'."
- :group 'org-export-e-html
- :type '(repeat (cons (string :tag "Character")
- (string :tag "HTML equivalent"))))
-
-(defcustom org-e-html-quotes
- '(("fr"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "&laquo;&nbsp;")
- ("\\(\\S-\\)\"" . "&nbsp;&raquo;")
- ("\\(\\s-\\|(\\|^\\)'" . "&rsquo;"))
- ("en"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "&ldquo;")
- ("\\(\\S-\\)\"" . "&rdquo;")
- ("\\(\\s-\\|(\\|^\\)'" . "&lsquo;")))
- "Alist for quotes to use when converting english double-quotes.
-
-The CAR of each item in this alist is the language code.
-The CDR of each item in this alist is a list of three CONS:
-- the first CONS defines the opening quote;
-- the second CONS defines the closing quote;
-- the last CONS defines single quotes.
-
-For each item in a CONS, the first string is a regexp
-for allowed characters before/after the quote, the second
-string defines the replacement string for this quote."
- :group 'org-export-e-html
- :type '(list
- (cons :tag "Opening quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))
- (cons :tag "Closing quote"
- (string :tag "Regexp for char after ")
- (string :tag "Replacement quote "))
- (cons :tag "Single quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))))
-
-
-;;;; Src Block
-
-(defcustom org-export-e-htmlize-output-type 'inline-css
- "Output type to be used by htmlize when formatting code snippets.
-Choices are `css', to export the CSS selectors only, or `inline-css', to
-export the CSS attribute values inline in the HTML. We use as default
-`inline-css', in order to make the resulting HTML self-containing.
-
-However, this will fail when using Emacs in batch mode for export, because
-then no rich font definitions are in place. It will also not be good if
-people with different Emacs setup contribute HTML files to a website,
-because the fonts will represent the individual setups. In these cases,
-it is much better to let Org/Htmlize assign classes only, and to use
-a style file to define the look of these classes.
-To get a start for your css file, start Emacs session and make sure that
-all the faces you are interested in are defined, for example by loading files
-in all modes you want. Then, use the command
-\\[org-export-e-htmlize-generate-css] to extract class definitions."
- :group 'org-export-e-htmlize
- :type '(choice (const css) (const inline-css)))
-
-(defcustom org-export-e-htmlize-css-font-prefix "org-"
- "The prefix for CSS class names for htmlize font specifications."
- :group 'org-export-e-htmlize
- :type 'string)
-
-(defcustom org-export-e-htmlized-org-css-url nil
- "URL pointing to a CSS file defining text colors for htmlized Emacs buffers.
-Normally when creating an htmlized version of an Org buffer, htmlize will
-create CSS to define the font colors. However, this does not work when
-converting in batch mode, and it also can look bad if different people
-with different fontification setup work on the same website.
-When this variable is non-nil, creating an htmlized version of an Org buffer
-using `org-export-as-org' will remove the internal CSS section and replace it
-with a link to this URL."
- :group 'org-export-e-htmlize
- :type '(choice
- (const :tag "Keep internal css" nil)
- (string :tag "URL or local href")))
-
-
-;;;; Table
-
-(defcustom org-e-html-table-tag
- "<table border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\">"
- "The HTML tag that is used to start a table.
-This must be a <table> tag, but you may change the options like
-borders and spacing."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-table-header-tags '("<th scope=\"%s\"%s>" . "</th>")
- "The opening tag for table header fields.
-This is customizable so that alignment options can be specified.
-The first %s will be filled with the scope of the field, either row or col.
-The second %s will be replaced by a style entry to align the field.
-See also the variable `org-e-html-table-use-header-tags-for-first-column'.
-See also the variable `org-e-html-table-align-individual-fields'."
- :group 'org-export-tables ; FIXME: change group?
- :type '(cons (string :tag "Opening tag") (string :tag "Closing tag")))
-
-(defcustom org-e-html-table-data-tags '("<td%s>" . "</td>")
- "The opening tag for table data fields.
-This is customizable so that alignment options can be specified.
-The first %s will be filled with the scope of the field, either row or col.
-The second %s will be replaced by a style entry to align the field.
-See also the variable `org-e-html-table-align-individual-fields'."
- :group 'org-export-tables
- :type '(cons (string :tag "Opening tag") (string :tag "Closing tag")))
-
-(defcustom org-e-html-table-row-tags '("<tr>" . "</tr>")
- "The opening tag for table data fields.
-This is customizable so that alignment options can be specified.
-Instead of strings, these can be Lisp forms that will be evaluated
-for each row in order to construct the table row tags. During evaluation,
-the variable `head' will be true when this is a header line, nil when this
-is a body line. And the variable `nline' will contain the line number,
-starting from 1 in the first header line. For example
-
- (setq org-e-html-table-row-tags
- (cons '(if head
- \"<tr>\"
- (if (= (mod nline 2) 1)
- \"<tr class=\\\"tr-odd\\\">\"
- \"<tr class=\\\"tr-even\\\">\"))
- \"</tr>\"))
-
-will give even lines the class \"tr-even\" and odd lines the class \"tr-odd\"."
- :group 'org-export-tables
- :type '(cons
- (choice :tag "Opening tag"
- (string :tag "Specify")
- (sexp))
- (choice :tag "Closing tag"
- (string :tag "Specify")
- (sexp))))
-
-(defcustom org-e-html-table-align-individual-fields t
- "Non-nil means attach style attributes for alignment to each table field.
-When nil, alignment will only be specified in the column tags, but this
-is ignored by some browsers (like Firefox, Safari). Opera does it right
-though."
- :group 'org-export-tables
- :type 'boolean)
-
-(defcustom org-e-html-table-use-header-tags-for-first-column nil
- "Non-nil means format column one in tables with header tags.
-When nil, also column one will use data tags."
- :group 'org-export-tables
- :type 'boolean)
-
-(defcustom org-e-html-table-caption-above t
- "When non-nil, place caption string at the beginning of the table.
-Otherwise, place it near the end."
- :group 'org-export-e-html
- :type 'boolean)
-
-
-;;;; Tags
-
-(defcustom org-e-html-tag-class-prefix ""
- "Prefix to class names for TODO keywords.
-Each tag gets a class given by the tag itself, with this prefix.
-The default prefix is empty because it is nice to just use the keyword
-as a class name. But if you get into conflicts with other, existing
-CSS classes, then this prefix can be very useful."
- :group 'org-export-e-html
- :type 'string)
-
-
-;;;; Template :: Generic
-
-(defcustom org-e-html-extension "html"
- "The extension for exported HTML files."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-xml-declaration
- '(("html" . "<?xml version=\"1.0\" encoding=\"%s\"?>")
- ("php" . "<?php echo \"<?xml version=\\\"1.0\\\" encoding=\\\"%s\\\" ?>\"; ?>"))
- "The extension for exported HTML files.
-%s will be replaced with the charset of the exported file.
-This may be a string, or an alist with export extensions
-and corresponding declarations."
- :group 'org-export-e-html
- :type '(choice
- (string :tag "Single declaration")
- (repeat :tag "Dependent on extension"
- (cons (string :tag "Extension")
- (string :tag "Declaration")))))
-
-(defcustom org-e-html-coding-system 'utf-8
- "Coding system for HTML export.
-Use utf-8 as the default value."
- :group 'org-export-e-html
- :type 'coding-system)
-
-(defcustom org-e-html-divs '("preamble" "content" "postamble")
- "The name of the main divs for HTML export.
-This is a list of three strings, the first one for the preamble
-DIV, the second one for the content DIV and the third one for the
-postamble DIV."
- :group 'org-export-e-html
- :type '(list
- (string :tag " Div for the preamble:")
- (string :tag " Div for the content:")
- (string :tag "Div for the postamble:")))
-
-
-;;;; Template :: Mathjax
-
-(defcustom org-e-html-mathjax-options
- '((path "http://orgmode.org/mathjax/MathJax.js")
- (scale "100")
- (align "center")
- (indent "2em")
- (mathml nil))
- "Options for MathJax setup.
-
-path The path where to find MathJax
-scale Scaling for the HTML-CSS backend, usually between 100 and 133
-align How to align display math: left, center, or right
-indent If align is not center, how far from the left/right side?
-mathml Should a MathML player be used if available?
- This is faster and reduces bandwidth use, but currently
- sometimes has lower spacing quality. Therefore, the default is
- nil. When browsers get better, this switch can be flipped.
-
-You can also customize this for each buffer, using something like
-
-#+MATHJAX: scale:\"133\" align:\"right\" mathml:t path:\"/MathJax/\""
- :group 'org-export-e-html
- :type '(list :greedy t
- (list :tag "path (the path from where to load MathJax.js)"
- (const :format " " path) (string))
- (list :tag "scale (scaling for the displayed math)"
- (const :format " " scale) (string))
- (list :tag "align (alignment of displayed equations)"
- (const :format " " align) (string))
- (list :tag "indent (indentation with left or right alignment)"
- (const :format " " indent) (string))
- (list :tag "mathml (should MathML display be used is possible)"
- (const :format " " mathml) (boolean))))
-
-(defcustom org-e-html-mathjax-template
- "<script type=\"text/javascript\" src=\"%PATH\">
-<!--/*--><![CDATA[/*><!--*/
- MathJax.Hub.Config({
- // Only one of the two following lines, depending on user settings
- // First allows browser-native MathML display, second forces HTML/CSS
- :MMLYES: config: [\"MMLorHTML.js\"], jax: [\"input/TeX\"],
- :MMLNO: jax: [\"input/TeX\", \"output/HTML-CSS\"],
- extensions: [\"tex2jax.js\",\"TeX/AMSmath.js\",\"TeX/AMSsymbols.js\",
- \"TeX/noUndefined.js\"],
- tex2jax: {
- inlineMath: [ [\"\\\\(\",\"\\\\)\"] ],
- displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"], [\"\\\\begin{displaymath}\",\"\\\\end{displaymath}\"] ],
- skipTags: [\"script\",\"noscript\",\"style\",\"textarea\",\"pre\",\"code\"],
- ignoreClass: \"tex2jax_ignore\",
- processEscapes: false,
- processEnvironments: true,
- preview: \"TeX\"
- },
- showProcessingMessages: true,
- displayAlign: \"%ALIGN\",
- displayIndent: \"%INDENT\",
-
- \"HTML-CSS\": {
- scale: %SCALE,
- availableFonts: [\"STIX\",\"TeX\"],
- preferredFont: \"TeX\",
- webFont: \"TeX\",
- imageFont: \"TeX\",
- showMathMenu: true,
- },
- MMLorHTML: {
- prefer: {
- MSIE: \"MML\",
- Firefox: \"MML\",
- Opera: \"HTML\",
- other: \"HTML\"
- }
- }
- });
-/*]]>*///-->
-</script>"
- "The MathJax setup for XHTML files."
- :group 'org-export-e-html
- :type 'string)
-
-
-;;;; Template :: Postamble
-
-(defcustom org-e-html-postamble 'auto
- "Non-nil means insert a postamble in HTML export.
-
-When `t', insert a string as defined by the formatting string in
-`org-e-html-postamble-format'. When set to a string, this
-string overrides `org-e-html-postamble-format'. When set to
-'auto, discard `org-e-html-postamble-format' and honor
-`org-export-author/email/creator-info' variables. When set to a
-function, apply this function and insert the returned string.
-The function takes the property list of export options as its
-only argument.
-
-Setting :html-postamble in publishing projects will take
-precedence over this variable."
- :group 'org-export-e-html
- :type '(choice (const :tag "No postamble" nil)
- (const :tag "Auto preamble" 'auto)
- (const :tag "Default formatting string" t)
- (string :tag "Custom formatting string")
- (function :tag "Function (must return a string)")))
-
-(defcustom org-e-html-postamble-format
- '(("en" "<p class=\"author\">Author: %a (%e)</p>
-<p class=\"date\">Date: %d</p>
-<p class=\"creator\">Generated by %c</p>
-<p class=\"xhtml-validation\">%v</p>
-"))
- "The format for the HTML postamble.
-
-%a stands for the author's name.
-%e stands for the author's email.
-%d stands for the date.
-%c will be replaced by information about Org/Emacs versions.
-%v will be replaced by `org-e-html-validation-link'.
-
-If you need to use a \"%\" character, you need to escape it
-like that: \"%%\"."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-validation-link
- "<a href=\"http://validator.w3.org/check?uri=referer\">Validate XHTML 1.0</a>"
- "Link to HTML validation service."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-creator-string
- (format "Generated by <a href=\"http://orgmode.org\">Org</a> mode %s in <a href=\"http://www.gnu.org/software/emacs/\">Emacs</a> %s."
- (if (fboundp 'org-version) (org-version) "(Unknown)")
- emacs-version)
- "String to insert at the end of the HTML document."
- :group 'org-export-e-html
- :type '(string :tag "Creator string"))
-
-
-;;;; Template :: Preamble
-
-(defcustom org-e-html-preamble t
- "Non-nil means insert a preamble in HTML export.
-
-When `t', insert a string as defined by one of the formatting
-strings in `org-e-html-preamble-format'. When set to a
-string, this string overrides `org-e-html-preamble-format'.
-When set to a function, apply this function and insert the
-returned string. The function takes the property list of export
-options as its only argument.
-
-Setting :html-preamble in publishing projects will take
-precedence over this variable."
- :group 'org-export-e-html
- :type '(choice (const :tag "No preamble" nil)
- (const :tag "Default preamble" t)
- (string :tag "Custom formatting string")
- (function :tag "Function (must return a string)")))
-
-(defcustom org-e-html-preamble-format '(("en" ""))
- "The format for the HTML preamble.
-
-%t stands for the title.
-%a stands for the author's name.
-%e stands for the author's email.
-%d stands for the date.
-
-If you need to use a \"%\" character, you need to escape it
-like that: \"%%\"."
- :group 'org-export-e-html
- :type 'string)
-
-(defcustom org-e-html-link-up ""
- "Where should the \"UP\" link of exported HTML pages lead?"
- :group 'org-export-e-html
- :type '(string :tag "File or URL"))
-
-(defcustom org-e-html-link-home ""
- "Where should the \"HOME\" link of exported HTML pages lead?"
- :group 'org-export-e-html
- :type '(string :tag "File or URL"))
-
-(defcustom org-e-html-home/up-format
- "<div id=\"org-div-home-and-up\" style=\"text-align:right;font-size:70%%;white-space:nowrap;\">
- <a accesskey=\"h\" href=\"%s\"> UP </a>
- |
- <a accesskey=\"H\" href=\"%s\"> HOME </a>
-</div>"
- "Snippet used to insert the HOME and UP links.
-This is a format string, the first %s will receive the UP link,
-the second the HOME link. If both `org-e-html-link-up' and
-`org-e-html-link-home' are empty, the entire snippet will be
-ignored."
- :group 'org-export-e-html
- :type 'string)
-
-
-;;;; Template :: Scripts
-
-(defcustom org-e-html-style-include-scripts t
- "Non-nil means include the JavaScript snippets in exported HTML files.
-The actual script is defined in `org-e-html-scripts' and should
-not be modified."
- :group 'org-export-e-html
- :type 'boolean)
-
-
-;;;; Template :: Styles
-
-(defcustom org-e-html-style-include-default t
- "Non-nil means include the default style in exported HTML files.
-The actual style is defined in `org-e-html-style-default' and should
-not be modified. Use the variables `org-e-html-style' to add
-your own style information."
- :group 'org-export-e-html
- :type 'boolean)
-;;;###autoload
-(put 'org-e-html-style-include-default 'safe-local-variable 'booleanp)
-
-(defcustom org-e-html-style ""
- "Org-wide style definitions for exported HTML files.
-
-This variable needs to contain the full HTML structure to provide a style,
-including the surrounding HTML tags. If you set the value of this variable,
-you should consider to include definitions for the following classes:
- title, todo, done, timestamp, timestamp-kwd, tag, target.
-
-For example, a valid value would be:
-
- <style type=\"text/css\">
- <![CDATA[
- p { font-weight: normal; color: gray; }
- h1 { color: black; }
- .title { text-align: center; }
- .todo, .timestamp-kwd { color: red; }
- .done { color: green; }
- ]]>
- </style>
-
-If you'd like to refer to an external style file, use something like
-
- <link rel=\"stylesheet\" type=\"text/css\" href=\"mystyles.css\">
-
-As the value of this option simply gets inserted into the HTML <head> header,
-you can \"misuse\" it to add arbitrary text to the header.
-See also the variable `org-e-html-style-extra'."
- :group 'org-export-e-html
- :type 'string)
-;;;###autoload
-(put 'org-e-html-style 'safe-local-variable 'stringp)
-
-(defcustom org-e-html-style-extra ""
- "Additional style information for HTML export.
-The value of this variable is inserted into the HTML buffer right after
-the value of `org-e-html-style'. Use this variable for per-file
-settings of style information, and do not forget to surround the style
-settings with <style>...</style> tags."
- :group 'org-export-e-html
- :type 'string)
-;;;###autoload
-(put 'org-e-html-style-extra 'safe-local-variable 'stringp)
-
-
-;;;; Todos
-
-(defcustom org-e-html-todo-kwd-class-prefix ""
- "Prefix to class names for TODO keywords.
-Each TODO keyword gets a class given by the keyword itself, with this prefix.
-The default prefix is empty because it is nice to just use the keyword
-as a class name. But if you get into conflicts with other, existing
-CSS classes, then this prefix can be very useful."
- :group 'org-export-e-html
- :type 'string)
-
-
-
-;;; Internal Functions
-
-(defun org-e-html-format-inline-image (src &optional
- caption label attr standalone-p)
- (let* ((id (if (not label) ""
- (format " id=\"%s\"" (org-export-solidify-link-text label))))
- (attr (concat attr
- (cond
- ((string-match "\\<alt=" (or attr "")) "")
- ((string-match "^ltxpng/" src)
- (format " alt=\"%s\""
- (org-e-html-encode-plain-text
- (org-find-text-property-in-string
- 'org-latex-src src))))
- (t (format " alt=\"%s\""
- (file-name-nondirectory src)))))))
- (cond
- (standalone-p
- (let ((img (format "<img src=\"%s\" %s/>" src attr)))
- (format "\n<div%s class=\"figure\">%s%s\n</div>"
- id (format "\n<p>%s</p>" img)
- (when caption (format "\n<p>%s</p>" caption)))))
- (t (format "<img src=\"%s\" %s/>" src (concat attr id))))))
-
-;;;; Bibliography
-
-(defun org-e-html-bibliography ()
- "Find bibliography, cut it out and return it."
- (catch 'exit
- (let (beg end (cnt 1) bib)
- (save-excursion
- (goto-char (point-min))
- (when (re-search-forward
- "^[ \t]*<div \\(id\\|class\\)=\"bibliography\"" nil t)
- (setq beg (match-beginning 0))
- (while (re-search-forward "</?div\\>" nil t)
- (setq cnt (+ cnt (if (string= (match-string 0) "<div") +1 -1)))
- (when (= cnt 0)
- (and (looking-at ">") (forward-char 1))
- (setq bib (buffer-substring beg (point)))
- (delete-region beg (point))
- (throw 'exit bib))))
- nil))))
-
-;;;; Table
-
-(defun org-e-html-splice-attributes (tag attributes)
- "Read attributes in string ATTRIBUTES, add and replace in HTML tag TAG."
- (if (not attributes)
- tag
- (let (oldatt newatt)
- (setq oldatt (org-extract-attributes-from-string tag)
- tag (pop oldatt)
- newatt (cdr (org-extract-attributes-from-string attributes)))
- (while newatt
- (setq oldatt (plist-put oldatt (pop newatt) (pop newatt))))
- (if (string-match ">" tag)
- (setq tag
- (replace-match (concat (org-attributes-to-string oldatt) ">")
- t t tag)))
- tag)))
-
-(defun org-export-splice-style (style extra)
- "Splice EXTRA into STYLE, just before \"</style>\"."
- (if (and (stringp extra)
- (string-match "\\S-" extra)
- (string-match "</style>" style))
- (concat (substring style 0 (match-beginning 0))
- "\n" extra "\n"
- (substring style (match-beginning 0)))
- style))
-
-(defun org-export-e-htmlize-region-for-paste (beg end)
- "Convert the region to HTML, using htmlize.el.
-This is much like `htmlize-region-for-paste', only that it uses
-the settings define in the org-... variables."
- (let* ((htmlize-output-type org-export-e-htmlize-output-type)
- (htmlize-css-name-prefix org-export-e-htmlize-css-font-prefix)
- (htmlbuf (htmlize-region beg end)))
- (unwind-protect
- (with-current-buffer htmlbuf
- (buffer-substring (plist-get htmlize-buffer-places 'content-start)
- (plist-get htmlize-buffer-places 'content-end)))
- (kill-buffer htmlbuf))))
-
-;;;###autoload
-(defun org-export-e-htmlize-generate-css ()
- "Create the CSS for all font definitions in the current Emacs session.
-Use this to create face definitions in your CSS style file that can then
-be used by code snippets transformed by htmlize.
-This command just produces a buffer that contains class definitions for all
-faces used in the current Emacs session. You can copy and paste the ones you
-need into your CSS file.
-
-If you then set `org-export-e-htmlize-output-type' to `css', calls to
-the function `org-export-e-htmlize-region-for-paste' will produce code
-that uses these same face definitions."
- (interactive)
- (require 'htmlize)
- (and (get-buffer "*html*") (kill-buffer "*html*"))
- (with-temp-buffer
- (let ((fl (face-list))
- (htmlize-css-name-prefix "org-")
- (htmlize-output-type 'css)
- f i)
- (while (setq f (pop fl)
- i (and f (face-attribute f :inherit)))
- (when (and (symbolp f) (or (not i) (not (listp i))))
- (insert (org-add-props (copy-sequence "1") nil 'face f))))
- (htmlize-region (point-min) (point-max))))
- (org-pop-to-buffer-same-window "*html*")
- (goto-char (point-min))
- (if (re-search-forward "<style" nil t)
- (delete-region (point-min) (match-beginning 0)))
- (if (re-search-forward "</style>" nil t)
- (delete-region (1+ (match-end 0)) (point-max)))
- (beginning-of-line 1)
- (if (looking-at " +") (replace-match ""))
- (goto-char (point-min)))
-
-(defun org-e-html-make-string (n string)
- (let (out) (dotimes (i n out) (setq out (concat string out)))))
-
-(defun org-e-html-toc-text (toc-entries)
- (let* ((prev-level (1- (nth 1 (car toc-entries))))
- (start-level prev-level))
- (concat
- (mapconcat
- (lambda (entry)
- (let ((headline (nth 0 entry))
- (level (nth 1 entry)))
- (concat
- (let* ((cnt (- level prev-level))
- (times (if (> cnt 0) (1- cnt) (- cnt)))
- rtn)
- (setq prev-level level)
- (concat
- (org-e-html-make-string
- times (cond ((> cnt 0) "\n<ul>\n<li>")
- ((< cnt 0) "</li>\n</ul>\n")))
- (if (> cnt 0) "\n<ul>\n<li>" "</li>\n<li>")))
- headline)))
- toc-entries "")
- (org-e-html-make-string
- (- prev-level start-level) "</li>\n</ul>\n"))))
-
-(defun* org-e-html-format-toc-headline
- (todo todo-type priority text tags
- &key level section-number headline-label &allow-other-keys)
- (let ((headline (concat
- section-number (and section-number ". ")
- text
- (and tags "&nbsp;&nbsp;&nbsp;") (org-e-html--tags tags))))
- (format "<a href=\"#%s\">%s</a>"
- (org-export-solidify-link-text headline-label)
- (if (not nil) headline
- (format "<span class=\"%s\">%s</span>" todo-type headline)))))
-
-(defun org-e-html-toc (depth info)
- (let* ((headlines (org-export-collect-headlines info depth))
- (toc-entries
- (loop for headline in headlines collect
- (list (org-e-html-format-headline--wrap
- headline info 'org-e-html-format-toc-headline)
- (org-export-get-relative-level headline info)))))
- (when toc-entries
- (concat
- "<div id=\"table-of-contents\">\n"
- (format "<h%d>%s</h%d>\n"
- org-e-html-toplevel-hlevel
- (org-e-html--translate "Table of Contents" info)
- org-e-html-toplevel-hlevel)
- "<div id=\"text-table-of-contents\">"
- (org-e-html-toc-text toc-entries)
- "</div>\n"
- "</div>\n"))))
-
-(defun org-e-html-fix-class-name (kwd) ; audit callers of this function
- "Turn todo keyword into a valid class name.
-Replaces invalid characters with \"_\"."
- (save-match-data
- (while (string-match "[^a-zA-Z0-9_]" kwd)
- (setq kwd (replace-match "_" t t kwd))))
- kwd)
-
-(defun org-e-html-format-footnote-reference (n def refcnt)
- (let ((extra (if (= refcnt 1) "" (format ".%d" refcnt))))
- (format org-e-html-footnote-format
- (let* ((id (format "fnr.%s%s" n extra))
- (href (format " href=\"#fn.%s\"" n))
- (attributes (concat " class=\"footref\"" href)))
- (org-e-html--anchor id n attributes)))))
-
-(defun org-e-html-format-footnotes-section (section-name definitions)
- (if (not definitions) ""
- (format org-e-html-footnotes-section section-name definitions)))
-
-(defun org-e-html-format-footnote-definition (fn)
- (let ((n (car fn)) (def (cdr fn)))
- (format
- "<tr>\n<td>%s</td>\n<td>%s</td>\n</tr>\n"
- (format org-e-html-footnote-format
- (let* ((id (format "fn.%s" n))
- (href (format " href=\"#fnr.%s\"" n))
- (attributes (concat " class=\"footnum\"" href)))
- (org-e-html--anchor id n attributes)))
- def)))
-
-(defun org-e-html-footnote-section (info)
- (let* ((fn-alist (org-export-collect-footnote-definitions
- (plist-get info :parse-tree) info))
-
- (fn-alist
- (loop for (n type raw) in fn-alist collect
- (cons n (if (eq (org-element-type raw) 'org-data)
- (org-trim (org-export-data raw info))
- (format "<p>%s</p>"
- (org-trim (org-export-data raw info))))))))
- (when fn-alist
- (org-e-html-format-footnotes-section
- (org-e-html--translate "Footnotes" info)
- (format
- "<table>\n%s\n</table>\n"
- (mapconcat 'org-e-html-format-footnote-definition fn-alist "\n"))))))
-
-(defun org-e-html-format-date (info)
- (let ((date (org-export-data (plist-get info :date) info)))
- (cond
- ((and date (string-match "%" date))
- (format-time-string date))
- (date date)
- (t (format-time-string "%Y-%m-%d %T %Z")))))
-
-(defun org-e-html--caption/label-string (caption label info)
- "Return caption and label HTML string for floats.
-
-CAPTION is a cons cell of secondary strings, the car being the
-standard caption and the cdr its short form. LABEL is a string
-representing the label. INFO is a plist holding contextual
-information.
-
-If there's no caption nor label, return the empty string.
-
-For non-floats, see `org-e-html--wrap-label'."
- (setq label nil) ;; FIXME
-
- (let ((label-str (if label (format "\\label{%s}" label) "")))
- (cond
- ((and (not caption) (not label)) "")
- ((not caption) (format "\\label{%s}\n" label))
- ;; Option caption format with short name.
- ((cdr caption)
- (format "\\caption[%s]{%s%s}\n"
- (org-export-data (cdr caption) info)
- label-str
- (org-export-data (car caption) info)))
- ;; Standard caption format.
- ;; (t (format "\\caption{%s%s}\n"
- ;; label-str
- ;; (org-export-data (car caption) info)))
- (t (org-export-data (car caption) info)))))
-
-(defun org-e-html--find-verb-separator (s)
- "Return a character not used in string S.
-This is used to choose a separator for constructs like \\verb."
- (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
- (loop for c across ll
- when (not (string-match (regexp-quote (char-to-string c)) s))
- return (char-to-string c))))
-
-(defun org-e-html--quotation-marks (text info)
- "Export quotation marks depending on language conventions.
-TEXT is a string containing quotation marks to be replaced. INFO
-is a plist used as a communication channel."
- (mapc (lambda(l)
- (let ((start 0))
- (while (setq start (string-match (car l) text start))
- (let ((new-quote (concat (match-string 1 text) (cdr l))))
- (setq text (replace-match new-quote t t text))))))
- (cdr (or (assoc (plist-get info :language) org-e-html-quotes)
- ;; Falls back on English.
- (assoc "en" org-e-html-quotes))))
- text)
-
-(defun org-e-html--wrap-label (element output)
- "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
-This function shouldn't be used for floats. See
-`org-e-html--caption/label-string'."
- ;; (let ((label (org-element-property :name element)))
- ;; (if (or (not output) (not label) (string= output "") (string= label ""))
- ;; output
- ;; (concat (format "\\label{%s}\n" label) output)))
- output)
-
-
-
-;;; Template
-
-(defun org-e-html-meta-info (info)
- (let* ((title (org-export-data (plist-get info :title) info))
- (author (and (plist-get info :with-author)
- (let ((auth (plist-get info :author)))
- (and auth (org-export-data auth info)))))
- (description (plist-get info :description))
- (keywords (plist-get info :keywords)))
- (concat
- (format "\n<title>%s</title>\n" title)
- (format
- "\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=%s\"/>"
- (or (and org-e-html-coding-system
- (fboundp 'coding-system-get)
- (coding-system-get org-e-html-coding-system
- 'mime-charset))
- "iso-8859-1"))
- (format "\n<meta name=\"title\" content=\"%s\"/>" title)
- (format "\n<meta name=\"generator\" content=\"Org-mode\"/>")
- (format "\n<meta name=\"generated\" content=\"%s\"/>"
- (org-e-html-format-date info))
- (format "\n<meta name=\"author\" content=\"%s\"/>" author)
- (format "\n<meta name=\"description\" content=\"%s\"/>" description)
- (format "\n<meta name=\"keywords\" content=\"%s\"/>" keywords))))
-
-(defun org-e-html-style (info)
- (concat
- "\n" (when (plist-get info :style-include-default) org-e-html-style-default)
- (plist-get info :style)
- (plist-get info :style-extra)
- "\n"
- (when (plist-get info :style-include-scripts)
- org-e-html-scripts)))
-
-(defun org-e-html-mathjax-config (info)
- "Insert the user setup into the matchjax template."
- (when (member (plist-get info :LaTeX-fragments) '(mathjax t))
- (let ((template org-e-html-mathjax-template)
- (options org-e-html-mathjax-options)
- (in-buffer (or (plist-get info :mathjax) ""))
- name val (yes " ") (no "// ") x)
- (mapc
- (lambda (e)
- (setq name (car e) val (nth 1 e))
- (if (string-match (concat "\\<" (symbol-name name) ":") in-buffer)
- (setq val (car (read-from-string
- (substring in-buffer (match-end 0))))))
- (if (not (stringp val)) (setq val (format "%s" val)))
- (if (string-match (concat "%" (upcase (symbol-name name))) template)
- (setq template (replace-match val t t template))))
- options)
- (setq val (nth 1 (assq 'mathml options)))
- (if (string-match (concat "\\<mathml:") in-buffer)
- (setq val (car (read-from-string
- (substring in-buffer (match-end 0))))))
- ;; Exchange prefixes depending on mathml setting
- (if (not val) (setq x yes yes no no x))
- ;; Replace cookies to turn on or off the config/jax lines
- (if (string-match ":MMLYES:" template)
- (setq template (replace-match yes t t template)))
- (if (string-match ":MMLNO:" template)
- (setq template (replace-match no t t template)))
- ;; Return the modified template
- template)))
-
-(defun org-e-html-preamble (info)
- (when (plist-get info :html-preamble)
- (let* ((title (org-export-data (plist-get info :title) info))
- (date (org-e-html-format-date info))
- (author (org-export-data (plist-get info :author) info))
- (email (plist-get info :email))
- (html-pre-real-contents
- (cond
- ((functionp (plist-get info :html-preamble))
- (with-temp-buffer
- (funcall (plist-get info :html-preamble))
- (buffer-string)))
- ((stringp (plist-get info :html-preamble))
- (format-spec (plist-get info :html-preamble)
- `((?t . ,title) (?a . ,author)
- (?d . ,date) (?e . ,email))))
- (t
- (format-spec
- (or (cadr (assoc (plist-get info :language)
- org-e-html-preamble-format))
- (cadr (assoc "en" org-e-html-preamble-format)))
- `((?t . ,title) (?a . ,author)
- (?d . ,date) (?e . ,email)))))))
- (when (not (equal html-pre-real-contents ""))
- (concat
- (format "
-<div id=\"%s\"> " (nth 0 org-e-html-divs))
- "
-"
- html-pre-real-contents
- "
-</div>")))))
-
-(defun org-e-html-postamble (info)
- (concat
- (when (and (not body-only)
- (plist-get info :html-postamble))
- (let* ((html-post (plist-get info :html-postamble))
- (date (org-e-html-format-date info))
- (author (let ((author (plist-get info :author)))
- (and author (org-export-data author info))))
- (email
- (mapconcat (lambda(e)
- (format "<a href=\"mailto:%s\">%s</a>" e e))
- (split-string (plist-get info :email) ",+ *")
- ", "))
- (html-validation-link (or org-e-html-validation-link ""))
- (creator-info org-export-creator-string))
- (concat
- ;; begin postamble
- "
-<div id=\"" (nth 2 org-e-html-divs) "\">"
- (cond
- ;; auto postamble
- ((eq (plist-get info :html-postamble) 'auto)
- (concat
- (when (plist-get info :time-stamp-file)
- (format "
-<p class=\"date\"> %s: %s </p> " (org-e-html--translate "Date" info) date))
- (when (and (plist-get info :with-author) author)
- (format "
-<p class=\"author\"> %s : %s</p>" (org-e-html--translate "Author" info) author))
- (when (and (plist-get info :with-email) email)
- (format "
-<p class=\"email\"> %s </p>" email))
- (when (plist-get info :with-creator)
- (format "
-<p class=\"creator\"> %s </p>" creator-info))
- html-validation-link "\n"))
- ;; postamble from a string
- ((stringp (plist-get info :html-postamble))
- (format-spec (plist-get info :html-postamble)
- `((?a . ,author) (?e . ,email)
- (?d . ,date) (?c . ,creator-info)
- (?v . ,html-validation-link))))
-
- ;; postamble from a function
- ((functionp (plist-get info :html-postamble))
- (with-temp-buffer
- (funcall (plist-get info :html-postamble))
- (buffer-string)))
- ;; default postamble
- (t
- (format-spec
- (or (cadr (assoc (plist-get info :language)
- org-e-html-postamble-format))
- (cadr (assoc "en" org-e-html-postamble-format)))
- `((?a . ,author) (?e . ,email)
- (?d . ,date) (?c . ,creator-info)
- (?v . ,html-validation-link)))))
- "
-</div>")))
- ;; org-e-html-html-helper-timestamp
- ))
-
-(defun org-e-html-template (contents info)
- "Return complete document string after HTML conversion.
-CONTENTS is the transcoded contents string. RAW-DATA is the
-original parsed data. INFO is a plist holding export options."
- (concat
- (format
- (or (and (stringp org-e-html-xml-declaration)
- org-e-html-xml-declaration)
- (cdr (assoc (plist-get info :html-extension)
- org-e-html-xml-declaration))
- (cdr (assoc "html" org-e-html-xml-declaration))
-
- "")
- (or (and org-e-html-coding-system
- (fboundp 'coding-system-get)
- (coding-system-get org-e-html-coding-system
- 'mime-charset))
- "iso-8859-1"))
- "
-<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"
- \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
- (format "
-<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"%s\" xml:lang=\"%s\"> "
- (plist-get info :language) (plist-get info :language))
- "
-<head>"
- (org-e-html-meta-info info) ; meta
- (org-e-html-style info) ; style
- (org-e-html-mathjax-config info) ; mathjax
- "
-</head>"
-
- "
-<body>"
- (let ((link-up (org-trim (plist-get info :link-up)))
- (link-home (org-trim (plist-get info :link-home))))
- (unless (and (string= link-up "") (string= link-up ""))
- (format org-e-html-home/up-format
- (or link-up link-home)
- (or link-home link-up))))
- ;; preamble
- (org-e-html-preamble info)
- ;; begin content
- (format "
-<div id=\"%s\">" (or org-e-html-content-div
- (nth 1 org-e-html-divs)))
- ;; document title
- (format "
-<h1 class=\"title\">%s</h1>\n" (org-export-data (plist-get info :title) info))
- ;; table of contents
- (let ((depth (plist-get info :with-toc)))
- (when depth (org-e-html-toc depth info)))
- ;; document contents
- contents
- ;; footnotes section
- (org-e-html-footnote-section info)
- ;; bibliography
- (org-e-html-bibliography)
- ;; end content
- (unless body-only
- "
-</div>")
-
- ;; postamble
- (org-e-html-postamble info)
-
- (unless body-only
- "
-</body>")
- "
-</html>"))
-
-(defun org-e-html--translate (s info)
- "Transcode string S in to HTML.
-INFO is a plist used as a communication channel.
-
-Lookup utf-8 equivalent of S in `org-export-dictionary' and
-replace all non-ascii characters with its numeric reference."
- (let ((s (org-export-translate s :utf-8 info)))
- ;; Protect HTML metacharacters.
- (setq s (org-e-html-encode-plain-text s))
- ;; Replace non-ascii characters with their numeric equivalents.
- (replace-regexp-in-string
- "[[:nonascii:]]"
- (lambda (m) (format "&#%d;" (encode-char (string-to-char m) 'ucs)))
- s t t)))
-
-;;;; Anchor
-
-(defun org-e-html--anchor (&optional id desc attributes)
- (let* ((name (and org-e-html-allow-name-attribute-in-anchors id))
- (attributes (concat (and id (format " id=\"%s\"" id))
- (and name (format " name=\"%s\"" name))
- attributes)))
- (format "<a%s>%s</a>" attributes (or desc ""))))
-
-;;;; Todo
-
-(defun org-e-html--todo (todo)
- (when todo
- (format "<span class=\"%s %s%s\">%s</span>"
- (if (member todo org-done-keywords) "done" "todo")
- org-e-html-todo-kwd-class-prefix (org-e-html-fix-class-name todo)
- todo)))
-
-;;;; Tags
-
-(defun org-e-html--tags (tags)
- (when tags
- (format "<span class=\"tag\">%s</span>"
- (mapconcat
- (lambda (tag)
- (format "<span class=\"%s\">%s</span>"
- (concat org-e-html-tag-class-prefix
- (org-e-html-fix-class-name tag))
- tag))
- tags "&nbsp;"))))
-
-;;;; Headline
-
-(defun* org-e-html-format-headline
- (todo todo-type priority text tags
- &key level section-number headline-label &allow-other-keys)
- (let ((section-number
- (when section-number
- (format "<span class=\"section-number-%d\">%s</span> "
- level section-number)))
- (todo (org-e-html--todo todo))
- (tags (org-e-html--tags tags)))
- (concat section-number todo (and todo " ") text
- (and tags "&nbsp;&nbsp;&nbsp;") tags)))
-
-;;;; Src Code
-
-(defun org-e-html-fontify-code (code lang)
- (when code
- (cond
- ;; Case 1: No lang. Possibly an example block.
- ((not lang)
- ;; Simple transcoding.
- (org-e-html-encode-plain-text code))
- ;; Case 2: No htmlize or an inferior version of htmlize
- ((not (and (require 'htmlize nil t) (fboundp 'htmlize-region-for-paste)))
- ;; Emit a warning.
- (message "Cannot fontify src block (htmlize.el >= 1.34 required)")
- ;; Simple transcoding.
- (org-e-html-encode-plain-text code))
- (t
- ;; Map language
- (setq lang (or (assoc-default lang org-src-lang-modes) lang))
- (let* ((lang-mode (and lang (intern (format "%s-mode" lang)))))
- (cond
- ;; Case 1: Language is not associated with any Emacs mode
- ((not (functionp lang-mode))
- ;; Simple transcoding.
- (org-e-html-encode-plain-text code))
- ;; Case 2: Default. Fontify code.
- (t
- ;; htmlize
- (setq code (with-temp-buffer
- (insert code)
- ;; Switch to language-specific mode.
- (funcall lang-mode)
- ;; Fontify buffer.
- (font-lock-fontify-buffer)
- ;; Remove formatting on newline characters.
- (save-excursion
- (let ((beg (point-min))
- (end (point-max)))
- (goto-char beg)
- (while (progn (end-of-line) (< (point) end))
- (put-text-property (point) (1+ (point)) 'face nil)
- (forward-char 1))))
- (org-src-mode)
- (set-buffer-modified-p nil)
- ;; Htmlize region.
- (org-export-e-htmlize-region-for-paste
- (point-min) (point-max))))
- ;; Strip any encolosing <pre></pre> tags.
- (if (string-match "<pre[^>]*>\n*\\([^\000]*\\)</pre>" code)
- (match-string 1 code)
- code))))))))
-
-(defun org-e-html-do-format-code
- (code &optional lang refs retain-labels num-start textarea-p)
- (when textarea-p
- (setq num-start nil refs nil lang nil))
- (let* ((code-lines (org-split-string code "\n"))
- (code-length (length code-lines))
- (num-fmt
- (and num-start
- (format "%%%ds: "
- (length (number-to-string (+ code-length num-start))))))
- (code (org-e-html-fontify-code code lang)))
- (assert (= code-length (length (org-split-string code "\n"))))
- (org-export-format-code
- code
- (lambda (loc line-num ref)
- (setq loc
- (concat
- ;; Add line number, if needed.
- (when num-start
- (format "<span class=\"linenr\">%s</span>"
- (format num-fmt line-num)))
- ;; Transcoded src line.
- loc
- ;; Add label, if needed.
- (when (and ref retain-labels) (format " (%s)" ref))))
- ;; Mark transcoded line as an anchor, if needed.
- (if (not ref) loc
- (format "<span id=\"coderef-%s\" class=\"coderef-off\">%s</span>"
- ref loc)))
- num-start refs)))
-
-(defun org-e-html-format-code (element info)
- (let* ((lang (org-element-property :language element))
- ;; (switches (org-element-property :switches element))
- (switches nil) ; FIXME
- (textarea-p (and switches (string-match "-t\\>" switches)))
- ;; Extract code and references.
- (code-info (org-export-unravel-code element))
- (code (car code-info))
- (refs (cdr code-info))
- ;; Does the src block contain labels?
- (retain-labels (org-element-property :retain-labels element))
- ;; Does it have line numbers?
- (num-start (case (org-element-property :number-lines element)
- (continued (org-export-get-loc element info))
- (new 0))))
- (org-e-html-do-format-code
- code lang refs retain-labels num-start textarea-p)))
-
-
-
-;;; Transcode Functions
-
-;;;; Bold
-
-(defun org-e-html-bold (bold contents info)
- "Transcode BOLD from Org to HTML.
-CONTENTS is the text with bold markup. INFO is a plist holding
-contextual information."
- (format (or (cdr (assq 'bold org-e-html-text-markup-alist)) "%s")
- contents))
-
-
-;;;; Center Block
-
-(defun org-e-html-center-block (center-block contents info)
- "Transcode a CENTER-BLOCK element from Org to HTML.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (org-e-html--wrap-label
- center-block
- (format "<div style=\"text-align: center\">\n%s</div>" contents)))
-
-
-;;;; Clock
-
-(defun org-e-html-clock (clock contents info)
- "Transcode a CLOCK element from Org to HTML.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (format "<p>
-<span class=\"timestamp-wrapper\">
-<span class=\"timestamp-kwd\">%s</span> <span class=\"timestamp\">%s</span>%s
-</span>
-</p>"
- org-clock-string
- (org-translate-time (org-element-property :value clock))
- (let ((time (org-element-property :time clock)))
- (and time (format " <span class=\"timestamp\">(%s)</span>" time)))))
-
-
-;;;; Code
-
-(defun org-e-html-code (code contents info)
- "Transcode CODE from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format (or (cdr (assq 'code org-e-html-text-markup-alist)) "%s")
- (org-element-property :value code)))
-
-
-;;;; Comment
-
-;; Comments are ignored.
-
-
-;;;; Comment Block
-
-;; Comment Blocks are ignored.
-
-
-;;;; Drawer
-
-(defun org-e-html-drawer (drawer contents info)
- "Transcode a DRAWER element from Org to HTML.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let* ((name (org-element-property :drawer-name drawer))
- (output (if (functionp org-e-html-format-drawer-function)
- (funcall org-e-html-format-drawer-function
- name contents)
- ;; If there's no user defined function: simply
- ;; display contents of the drawer.
- contents)))
- (org-e-html--wrap-label drawer output)))
-
-
-;;;; Dynamic Block
-
-(defun org-e-html-dynamic-block (dynamic-block contents info)
- "Transcode a DYNAMIC-BLOCK element from Org to HTML.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information. See `org-export-data'."
- (org-e-html--wrap-label dynamic-block contents))
-
-
-;;;; Entity
-
-(defun org-e-html-entity (entity contents info)
- "Transcode an ENTITY object from Org to HTML.
-CONTENTS are the definition itself. INFO is a plist holding
-contextual information."
- (org-element-property :html entity))
-
-
-;;;; Example Block
-
-(defun org-e-html-example-block (example-block contents info)
- "Transcode a EXAMPLE-BLOCK element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let* ((options (or (org-element-property :options example-block) ""))
- (lang (org-element-property :language example-block))
- (caption (org-element-property :caption example-block))
- (label (org-element-property :name example-block))
- (caption-str (org-e-html--caption/label-string caption label info))
- (attr (mapconcat #'identity
- (org-element-property :attr_html example-block)
- " "))
- ;; (switches (org-element-property :switches example-block))
- (switches nil) ; FIXME
- (textarea-p (and switches (string-match "-t\\>" switches)))
- (code (org-e-html-format-code example-block info)))
- (cond
- (textarea-p
- (let ((cols (if (not (string-match "-w[ \t]+\\([0-9]+\\)" switches))
- 80 (string-to-number (match-string 1 switches))))
- (rows (if (string-match "-h[ \t]+\\([0-9]+\\)" switches)
- (string-to-number (match-string 1 switches))
- (org-count-lines code))))
- (format
- "<p>\n<textarea cols=\"%d\" rows=\"%d\">\n%s</textarea>\n</p>"
- cols rows code)))
- (t (format "<pre class=\"example\">\n%s</pre>" code)))))
-
-
-;;;; Export Snippet
-
-(defun org-e-html-export-snippet (export-snippet contents info)
- "Transcode a EXPORT-SNIPPET object from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (eq (org-export-snippet-backend export-snippet) 'e-html)
- (org-element-property :value export-snippet)))
-
-
-;;;; Export Block
-
-(defun org-e-html-export-block (export-block contents info)
- "Transcode a EXPORT-BLOCK element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (string= (org-element-property :type export-block) "HTML")
- (org-remove-indentation (org-element-property :value export-block))))
-
-
-;;;; Fixed Width
-
-(defun org-e-html-fixed-width (fixed-width contents info)
- "Transcode a FIXED-WIDTH element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-html--wrap-label
- fixed-width
- (format "<pre class=\"example\">\n%s</pre>"
- (org-e-html-do-format-code
- (org-remove-indentation
- (org-element-property :value fixed-width))))))
-
-
-;;;; Footnote Definition
-
-;; Footnote Definitions are ignored.
-
-
-;;;; Footnote Reference
-
-(defun org-e-html-footnote-reference (footnote-reference contents info)
- "Transcode a FOOTNOTE-REFERENCE element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (concat
- ;; Insert separator between two footnotes in a row.
- (let ((prev (org-export-get-previous-element footnote-reference info)))
- (when (eq (org-element-type prev) 'footnote-reference)
- org-e-html-footnote-separator))
- (cond
- ((not (org-export-footnote-first-reference-p footnote-reference info))
- (org-e-html-format-footnote-reference
- (org-export-get-footnote-number footnote-reference info)
- "IGNORED" 100))
- ;; Inline definitions are secondary strings.
- ((eq (org-element-property :type footnote-reference) 'inline)
- (org-e-html-format-footnote-reference
- (org-export-get-footnote-number footnote-reference info)
- "IGNORED" 1))
- ;; Non-inline footnotes definitions are full Org data.
- (t (org-e-html-format-footnote-reference
- (org-export-get-footnote-number footnote-reference info)
- "IGNORED" 1)))))
-
-
-;;;; Headline
-
-(defun org-e-html-format-headline--wrap (headline info
- &optional format-function
- &rest extra-keys)
- "Transcode an HEADLINE element from Org to HTML.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- (let* ((level (+ (org-export-get-relative-level headline info)
- (1- org-e-html-toplevel-hlevel)))
- (headline-number (org-export-get-headline-number headline info))
- (section-number (and (org-export-numbered-headline-p headline info)
- (mapconcat 'number-to-string
- headline-number ".")))
- (todo (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword headline)))
- (and todo (org-export-data todo info)))))
- (todo-type (and todo (org-element-property :todo-type headline)))
- (priority (and (plist-get info :with-priority)
- (org-element-property :priority headline)))
- (text (org-export-data (org-element-property :title headline) info))
- (tags (and (plist-get info :with-tags)
- (org-export-get-tags headline info)))
- (headline-label (or (org-element-property :custom-id headline)
- (concat "sec-" (mapconcat 'number-to-string
- headline-number "-"))))
- (format-function (cond
- ((functionp format-function) format-function)
- ((functionp org-e-html-format-headline-function)
- (function*
- (lambda (todo todo-type priority text tags
- &allow-other-keys)
- (funcall org-e-html-format-headline-function
- todo todo-type priority text tags))))
- (t 'org-e-html-format-headline))))
- (apply format-function
- todo todo-type priority text tags
- :headline-label headline-label :level level
- :section-number section-number extra-keys)))
-
-(defun org-e-html-headline (headline contents info)
- "Transcode an HEADLINE element from Org to HTML.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- ;; Empty contents?
- (setq contents (or contents ""))
- (let* ((numberedp (org-export-numbered-headline-p headline info))
- (level (org-export-get-relative-level headline info))
- (text (org-export-data (org-element-property :title headline) info))
- (todo (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword headline)))
- (and todo (org-export-data todo info)))))
- (todo-type (and todo (org-element-property :todo-type headline)))
- (tags (and (plist-get info :with-tags)
- (org-export-get-tags headline info)))
- (priority (and (plist-get info :with-priority)
- (org-element-property :priority headline)))
- (section-number (and (org-export-numbered-headline-p headline info)
- (mapconcat 'number-to-string
- (org-export-get-headline-number
- headline info) ".")))
- ;; Create the headline text.
- (full-text (org-e-html-format-headline--wrap headline info)))
- (cond
- ;; Case 1: This is a footnote section: ignore it.
- ((org-element-property :footnote-section-p headline) nil)
- ;; Case 2. This is a deep sub-tree: export it as a list item.
- ;; Also export as items headlines for which no section
- ;; format has been found.
- ((org-export-low-level-p headline info) ; FIXME (or (not section-fmt))
- ;; Build the real contents of the sub-tree.
- (let* ((type (if numberedp 'unordered 'unordered)) ; FIXME
- (itemized-body (org-e-html-format-list-item
- contents type nil nil full-text)))
- (concat
- (and (org-export-first-sibling-p headline info)
- (org-e-html-begin-plain-list type))
- itemized-body
- (and (org-export-last-sibling-p headline info)
- (org-e-html-end-plain-list type)))))
- ;; Case 3. Standard headline. Export it as a section.
- (t
- (let* ((section-number (mapconcat 'number-to-string
- (org-export-get-headline-number
- headline info) "-"))
- (ids (remove 'nil
- (list (org-element-property :custom-id headline)
- (concat "sec-" section-number)
- (org-element-property :id headline))))
- (preferred-id (car ids))
- (extra-ids (cdr ids))
- (extra-class (org-element-property :html-container-class headline))
- (level1 (+ level (1- org-e-html-toplevel-hlevel))))
- (format "<div id=\"%s\" class=\"%s\">%s%s</div>\n"
- (format "outline-container-%s"
- (or (org-element-property :custom-id headline)
- section-number))
- (concat (format "outline-%d" level1) (and extra-class " ")
- extra-class)
- (format "\n<h%d id=\"%s\">%s%s</h%d>\n"
- level1
- preferred-id
- (mapconcat
- (lambda (x)
- (let ((id (org-export-solidify-link-text
- (if (org-uuidgen-p x) (concat "ID-" x)
- x))))
- (org-e-html--anchor id)))
- extra-ids "")
- full-text
- level1)
- contents))))))
-
-
-;;;; Horizontal Rule
-
-(defun org-e-html-horizontal-rule (horizontal-rule contents info)
- "Transcode an HORIZONTAL-RULE object from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((attr (mapconcat #'identity
- (org-element-property :attr_html horizontal-rule)
- " ")))
- (org-e-html--wrap-label horizontal-rule "<hr/>")))
-
-
-;;;; Inline Babel Call
-
-;; Inline Babel Calls are ignored.
-
-
-;;;; Inline Src Block
-
-(defun org-e-html-inline-src-block (inline-src-block contents info)
- "Transcode an INLINE-SRC-BLOCK element from Org to HTML.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((org-lang (org-element-property :language inline-src-block))
- (code (org-element-property :value inline-src-block))
- (separator (org-e-html--find-verb-separator code)))
- (error "FIXME")))
-
-
-;;;; Inlinetask
-
-(defun org-e-html-format-section (text class &optional id)
- (let ((extra (concat (when id (format " id=\"%s\"" id)))))
- (concat (format "<div class=\"%s\"%s>\n" class extra) text "</div>\n")))
-
-(defun org-e-html-inlinetask (inlinetask contents info)
- "Transcode an INLINETASK element from Org to HTML.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (cond
- ;; If `org-e-html-format-inlinetask-function' is provided, call it
- ;; with appropriate arguments.
- ((functionp org-e-html-format-inlinetask-function)
- (let ((format-function
- (function*
- (lambda (todo todo-type priority text tags
- &key contents &allow-other-keys)
- (funcall org-e-html-format-inlinetask-function
- todo todo-type priority text tags contents)))))
- (org-e-html-format-headline--wrap
- inlinetask info format-function :contents contents)))
- ;; Otherwise, use a default template.
- (t (org-e-html--wrap-label
- inlinetask
- (format
- "<div class=\"inlinetask\">\n<b>%s</b><br/>\n%s</div>"
- (org-e-html-format-headline--wrap inlinetask info)
- contents)))))
-
-
-;;;; Italic
-
-(defun org-e-html-italic (italic contents info)
- "Transcode ITALIC from Org to HTML.
-CONTENTS is the text with italic markup. INFO is a plist holding
-contextual information."
- (format (or (cdr (assq 'italic org-e-html-text-markup-alist)) "%s") contents))
-
-
-;;;; Item
-
-(defun org-e-html-checkbox (checkbox)
- (case checkbox (on "<code>[X]</code>")
- (off "<code>[&nbsp;]</code>")
- (trans "<code>[-]</code>")
- (t "")))
-
-(defun org-e-html-format-list-item (contents type checkbox
- &optional term-counter-id
- headline)
- (let ((checkbox (concat (org-e-html-checkbox checkbox) (and checkbox " "))))
- (concat
- (case type
- (ordered
- (let* ((counter term-counter-id)
- (extra (if counter (format " value=\"%s\"" counter) "")))
- (format "<li%s>" extra)))
- (unordered
- (let* ((id term-counter-id)
- (extra (if id (format " id=\"%s\"" id) "")))
- (concat
- (format "<li%s>" extra)
- (when headline (concat headline "<br/>")))))
- (descriptive
- (let* ((term term-counter-id))
- (setq term (or term "(no term)"))
- ;; Check-boxes in descriptive lists are associated to tag.
- (concat (format "<dt> %s </dt>"
- (concat checkbox term))
- "<dd>"))))
- (unless (eq type 'descriptive) checkbox)
- contents
- (case type
- (ordered "</li>")
- (unordered "</li>")
- (descriptive "</dd>")))))
-
-(defun org-e-html-item (item contents info)
- "Transcode an ITEM element from Org to HTML.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((plain-list (org-export-get-parent item))
- (type (org-element-property :type plain-list))
- (counter (org-element-property :counter item))
- (checkbox (org-element-property :checkbox item))
- (tag (let ((tag (org-element-property :tag item)))
- (and tag (org-export-data tag info)))))
- (org-e-html-format-list-item
- contents type checkbox (or tag counter))))
-
-
-;;;; Keyword
-
-(defun org-e-html-keyword (keyword contents info)
- "Transcode a KEYWORD element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((key (org-element-property :key keyword))
- (value (org-element-property :value keyword)))
- (cond
- ((string= key "HTML") value)
- ((string= key "INDEX") (format "\\index{%s}" value))
- ;; Invisible targets.
- ((string= key "TARGET") nil)
- ((string= key "TOC")
- (let ((value (downcase value)))
- (cond
- ((string-match "\\<headlines\\>" value)
- (let ((depth (or (and (string-match "[0-9]+" value)
- (string-to-number (match-string 0 value)))
- (plist-get info :with-toc))))
- (org-e-html-toc depth info)))
- ((string= "tables" value) "\\listoftables")
- ((string= "figures" value) "\\listoffigures")
- ((string= "listings" value)
- (cond
- ;; At the moment, src blocks with a caption are wrapped
- ;; into a figure environment.
- (t "\\listoffigures")))))))))
-
-
-;;;; Latex Environment
-
-(defun org-e-html-format-latex (latex-frag processing-type)
- (let* ((cache-relpath
- (concat "ltxpng/" (file-name-sans-extension
- (file-name-nondirectory (buffer-file-name)))))
- (cache-dir (file-name-directory (buffer-file-name )))
- (display-msg "Creating LaTeX Image..."))
-
- (with-temp-buffer
- (insert latex-frag)
- (org-format-latex cache-relpath cache-dir nil display-msg
- nil nil processing-type)
- (buffer-string))))
-
-(defun org-e-html-latex-environment (latex-environment contents info)
- "Transcode a LATEX-ENVIRONMENT element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-html--wrap-label
- latex-environment
- (let ((processing-type (plist-get info :LaTeX-fragments))
- (latex-frag (org-remove-indentation
- (org-element-property :value latex-environment)))
- (caption (org-e-html--caption/label-string
- (org-element-property :caption latex-environment)
- (org-element-property :name latex-environment)
- info))
- (attr nil) ; FIXME
- (label (org-element-property :name latex-environment)))
- (cond
- ((memq processing-type '(t mathjax))
- (org-e-html-format-latex latex-frag 'mathjax))
- ((eq processing-type 'dvipng)
- (let* ((formula-link (org-e-html-format-latex
- latex-frag processing-type)))
- (when (and formula-link
- (string-match "file:\\([^]]*\\)" formula-link))
- (org-e-html-format-inline-image
- (match-string 1 formula-link) caption label attr t))))
- (t latex-frag)))))
-
-
-;;;; Latex Fragment
-
-(defun org-e-html-latex-fragment (latex-fragment contents info)
- "Transcode a LATEX-FRAGMENT object from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((latex-frag (org-element-property :value latex-fragment))
- (processing-type (plist-get info :LaTeX-fragments)))
- (case processing-type
- ((t mathjax)
- (org-e-html-format-latex latex-frag 'mathjax))
- (dvipng
- (let* ((formula-link (org-e-html-format-latex
- latex-frag processing-type)))
- (when (and formula-link
- (string-match "file:\\([^]]*\\)" formula-link))
- (org-e-html-format-inline-image
- (match-string 1 formula-link)))))
- (t latex-frag))))
-
-;;;; Line Break
-
-(defun org-e-html-line-break (line-break contents info)
- "Transcode a LINE-BREAK object from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- "<br/>")
-
-
-;;;; Link
-
-(defun org-e-html-link--inline-image (link desc info)
- "Return HTML code for an inline image.
-LINK is the link pointing to the inline image. INFO is a plist
-used as a communication channel."
- (let* ((type (org-element-property :type link))
- (raw-path (org-element-property :path link))
- (path (cond ((member type '("http" "https"))
- (concat type ":" raw-path))
- ((file-name-absolute-p raw-path)
- (expand-file-name raw-path))
- (t raw-path)))
- (parent (org-export-get-parent-element link))
- (caption (org-e-html--caption/label-string
- (org-element-property :caption parent)
- (org-element-property :name parent)
- info))
- (label (org-element-property :name parent))
- ;; Retrieve latex attributes from the element around.
- (attr (let ((raw-attr
- (mapconcat #'identity
- (org-element-property :attr_html parent)
- " ")))
- (unless (string= raw-attr "") raw-attr))))
- ;; Now clear ATTR from any special keyword and set a default
- ;; value if nothing is left.
- (setq attr (if (not attr) "" (org-trim attr)))
- ;; Return proper string, depending on DISPOSITION.
- (org-e-html-format-inline-image
- path caption label attr (org-e-html-standalone-image-p link info))))
-
-(defvar org-e-html-standalone-image-predicate)
-(defun org-e-html-standalone-image-p (element info &optional predicate)
- "Test if ELEMENT is a standalone image for the purpose HTML export.
-INFO is a plist holding contextual information.
-
-Return non-nil, if ELEMENT is of type paragraph and it's sole
-content, save for whitespaces, is a link that qualifies as an
-inline image.
-
-Return non-nil, if ELEMENT is of type link and it's containing
-paragraph has no other content save for leading and trailing
-whitespaces.
-
-Return nil, otherwise.
-
-Bind `org-e-html-standalone-image-predicate' to constrain
-paragraph further. For example, to check for only captioned
-standalone images, do the following.
-
- \(setq org-e-html-standalone-image-predicate
- \(lambda \(paragraph\)
- \(org-element-property :caption paragraph\)\)\)
-"
- (let ((paragraph (case (org-element-type element)
- (paragraph element)
- (link (and (org-export-inline-image-p
- element org-e-html-inline-image-rules)
- (org-export-get-parent element)))
- (t nil))))
- (when paragraph
- (assert (eq (org-element-type paragraph) 'paragraph))
- (when (or (not (and (boundp 'org-e-html-standalone-image-predicate)
- (functionp org-e-html-standalone-image-predicate)))
- (funcall org-e-html-standalone-image-predicate paragraph))
- (let ((contents (org-element-contents paragraph)))
- (loop for x in contents
- with inline-image-count = 0
- always (cond
- ((eq (org-element-type x) 'plain-text)
- (not (org-string-nw-p x)))
- ((eq (org-element-type x) 'link)
- (when (org-export-inline-image-p
- x org-e-html-inline-image-rules)
- (= (incf inline-image-count) 1)))
- (t nil))))))))
-
-(defun org-e-html-link (link desc info)
- "Transcode a LINK object from Org to HTML.
-
-DESC is the description part of the link, or the empty string.
-INFO is a plist holding contextual information. See
-`org-export-data'."
- (let* ((--link-org-files-as-html-maybe
- (function
- (lambda (raw-path info)
- "Treat links to `file.org' as links to `file.html', if needed.
- See `org-e-html-link-org-files-as-html'."
- (cond
- ((and org-e-html-link-org-files-as-html
- (string= ".org"
- (downcase (file-name-extension raw-path "."))))
- (concat (file-name-sans-extension raw-path) "."
- (plist-get info :html-extension)))
- (t raw-path)))))
- (type (org-element-property :type link))
- (raw-path (org-element-property :path link))
- ;; Ensure DESC really exists, or set it to nil.
- (desc (and (not (string= desc "")) desc))
- (path (cond
- ((member type '("http" "https" "ftp" "mailto"))
- (concat type ":" raw-path))
- ((string= type "file")
- ;; Extract just the file path and strip all other
- ;; components.
- (when (string-match "\\(.+\\)::.+" raw-path)
- (setq raw-path (match-string 1 raw-path)))
- ;; Treat links to ".org" files as ".html", if needed.
- (setq raw-path (funcall --link-org-files-as-html-maybe
- raw-path info))
- ;; If file path is absolute, prepend it with protocol
- ;; component - "file://".
- (if (not (file-name-absolute-p raw-path)) raw-path
- (concat "file://" (expand-file-name raw-path))))
- (t raw-path)))
- ;; Extract attributes from parent's paragraph.
- (attributes
- (let ((attr (mapconcat
- 'identity
- (org-element-property
- :attr_html (org-export-get-parent-element link))
- " ")))
- (if attr (concat " " attr) "")))
- protocol)
- (cond
- ;; Image file.
- ((and (or (eq t org-e-html-inline-images)
- (and org-e-html-inline-images (not desc)))
- (org-export-inline-image-p link org-e-html-inline-image-rules))
- (org-e-html-link--inline-image link desc info))
- ;; Radio target: Transcode target's contents and use them as
- ;; link's description.
- ((string= type "radio")
- (let ((destination (org-export-resolve-radio-link link info)))
- (when destination
- (format "<a href=\"#%s\"%s>%s</a>"
- (org-export-solidify-link-text path)
- attributes
- (org-export-data (org-element-contents destination) info)))))
- ;; Links pointing to an headline: Find destination and build
- ;; appropriate referencing command.
- ((member type '("custom-id" "fuzzy" "id"))
- (let ((destination (if (string= type "fuzzy")
- (org-export-resolve-fuzzy-link link info)
- (org-export-resolve-id-link link info))))
- (case (org-element-type destination)
- ;; ID link points to an external file.
- (plain-text
- (assert (org-uuidgen-p path))
- (let ((fragment (concat "ID-" path))
- ;; Treat links to ".org" files as ".html", if needed.
- (path (funcall --link-org-files-as-html-maybe
- destination info)))
- (format "<a href=\"%s#%s\"%s>%s</a>"
- path fragment attributes (or desc destination))))
- ;; Fuzzy link points nowhere.
- ((nil)
- (format "<i>%s</i>"
- (or desc
- (org-export-data
- (org-element-property :raw-link link) info))))
- ;; Fuzzy link points to an invisible target.
- (keyword nil)
- ;; Link points to an headline.
- (headline
- (let ((href
- ;; What href to use?
- (cond
- ;; Case 1: Headline is linked via it's CUSTOM_ID
- ;; property. Use CUSTOM_ID.
- ((string= type "custom-id")
- (org-element-property :custom-id destination))
- ;; Case 2: Headline is linked via it's ID property
- ;; or through other means. Use the default href.
- ((member type '("id" "fuzzy"))
- (format "sec-%s"
- (mapconcat 'number-to-string
- (org-export-get-headline-number
- destination info) "-")))
- (t (error "Shouldn't reach here"))))
- ;; What description to use?
- (desc
- ;; Case 1: Headline is numbered and LINK has no
- ;; description or LINK's description matches
- ;; headline's title. Display section number.
- (if (and (org-export-numbered-headline-p destination info)
- (or (not desc)
- (string= desc (org-element-property
- :raw-value destination))))
- (mapconcat 'number-to-string
- (org-export-get-headline-number
- destination info) ".")
- ;; Case 2: Either the headline is un-numbered or
- ;; LINK has a custom description. Display LINK's
- ;; description or headline's title.
- (or desc (org-export-data (org-element-property
- :title destination) info)))))
- (format "<a href=\"#%s\"%s>%s</a>"
- (org-export-solidify-link-text href) attributes desc)))
- ;; Fuzzy link points to a target. Do as above.
- (t
- (let ((path (org-export-solidify-link-text path)) number)
- (unless desc
- (setq number (cond
- ((org-e-html-standalone-image-p destination info)
- (org-export-get-ordinal
- (assoc 'link (org-element-contents destination))
- info 'link 'org-e-html-standalone-image-p))
- (t (org-export-get-ordinal destination info))))
- (setq desc (when number
- (if (atom number) (number-to-string number)
- (mapconcat 'number-to-string number ".")))))
- (format "<a href=\"#%s\"%s>%s</a>"
- path attributes (or desc "FIXME")))))))
- ;; Coderef: replace link with the reference name or the
- ;; equivalent line number.
- ((string= type "coderef")
- (let ((fragment (concat "coderef-" path)))
- (format "<a href=\"#%s\" %s%s>%s</a>"
- fragment
- (format (concat "class=\"coderef\""
- " onmouseover=\"CodeHighlightOn(this, '%s');\""
- " onmouseout=\"CodeHighlightOff(this, '%s');\"")
- fragment fragment)
- attributes
- (format (org-export-get-coderef-format path desc)
- (org-export-resolve-coderef path info)))))
- ;; Link type is handled by a special function.
- ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
- (funcall protocol (org-link-unescape path) desc 'html))
- ;; External link with a description part.
- ((and path desc) (format "<a href=\"%s\"%s>%s</a>" path attributes desc))
- ;; External link without a description part.
- (path (format "<a href=\"%s\"%s>%s</a>" path attributes path))
- ;; No path, only description. Try to do something useful.
- (t (format "<i>%s</i>" desc)))))
-
-
-;;;; Babel Call
-
-;; Babel Calls are ignored.
-
-
-;;;; Macro
-
-(defun org-e-html-macro (macro contents info)
- "Transcode a MACRO element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- ;; Use available tools.
- (org-export-expand-macro macro info))
-
-
-;;;; Paragraph
-
-(defun org-e-html-paragraph (paragraph contents info)
- "Transcode a PARAGRAPH element from Org to HTML.
-CONTENTS is the contents of the paragraph, as a string. INFO is
-the plist used as a communication channel."
- (let* ((style nil) ; FIXME
- (class (cdr (assoc style '((footnote . "footnote")
- (verse . nil)))))
- (extra (if class (format " class=\"%s\"" class) ""))
- (parent (org-export-get-parent paragraph)))
- (cond
- ((and (eq (org-element-type parent) 'item)
- (= (org-element-property :begin paragraph)
- (org-element-property :contents-begin parent)))
- ;; leading paragraph in a list item have no tags
- contents)
- ((org-e-html-standalone-image-p paragraph info)
- ;; standalone image
- contents)
- (t (format "<p%s>\n%s</p>" extra contents)))))
-
-
-;;;; Plain List
-
-(defun org-e-html-begin-plain-list (type &optional arg1)
- (case type
- (ordered
- (format "<ol%s>" (if arg1 ; FIXME
- (format " start=\"%d\"" arg1)
- "")))
- (unordered "<ul>")
- (descriptive "<dl>")))
-
-(defun org-e-html-end-plain-list (type)
- (case type
- (ordered "</ol>")
- (unordered "</ul>")
- (descriptive "</dl>")))
-
-(defun org-e-html-plain-list (plain-list contents info)
- "Transcode a PLAIN-LIST element from Org to HTML.
-CONTENTS is the contents of the list. INFO is a plist holding
-contextual information."
- (let* (arg1 ;; FIXME
- (type (org-element-property :type plain-list))
- (attr (mapconcat #'identity
- (org-element-property :attr_html plain-list)
- " ")))
- (org-e-html--wrap-label
- plain-list (format "%s\n%s%s"
- (org-e-html-begin-plain-list type)
- contents (org-e-html-end-plain-list type)))))
-
-;;;; Plain Text
-
-(defun org-e-html-convert-special-strings (string)
- "Convert special characters in STRING to HTML."
- (let ((all org-e-html-special-string-regexps)
- e a re rpl start)
- (while (setq a (pop all))
- (setq re (car a) rpl (cdr a) start 0)
- (while (string-match re string start)
- (setq string (replace-match rpl t nil string))))
- string))
-
-(defun org-e-html-encode-plain-text (text)
- "Convert plain text characters to HTML equivalent.
-Possible conversions are set in `org-export-html-protect-char-alist'."
- (mapc
- (lambda (pair)
- (setq text (replace-regexp-in-string (car pair) (cdr pair) text t t)))
- org-e-html-protect-char-alist)
- text)
-
-(defun org-e-html-plain-text (text info)
- "Transcode a TEXT string from Org to HTML.
-TEXT is the string to transcode. INFO is a plist holding
-contextual information."
- ;; Protect following characters: <, >, &.
- (setq text (org-e-html-encode-plain-text text))
- ;; Handle quotation marks.
- (setq text (org-e-html--quotation-marks text info))
- ;; Handle special strings.
- (when (plist-get info :with-special-strings)
- (setq text (org-e-html-convert-special-strings text)))
- ;; Handle break preservation if required.
- (when (plist-get info :preserve-breaks)
- (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
- text)))
- ;; Return value.
- text)
-
-
-;; Planning
-
-(defun org-e-html-planning (planning contents info)
- "Transcode a PLANNING element from Org to HTML.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (let ((span-fmt "<span class=\"timestamp-kwd\">%s</span> <span class=\"timestamp\">%s</span>"))
- (format
- "<p><span class=\"timestamp-wrapper\">%s</span></p>"
- (mapconcat
- 'identity
- (delq nil
- (list
- (let ((closed (org-element-property :closed planning)))
- (when closed
- (format span-fmt org-closed-string
- (org-translate-time closed))))
- (let ((deadline (org-element-property :deadline planning)))
- (when deadline
- (format span-fmt org-deadline-string
- (org-translate-time deadline))))
- (let ((scheduled (org-element-property :scheduled planning)))
- (when scheduled
- (format span-fmt org-scheduled-string
- (org-translate-time scheduled))))))
- " "))))
-
-
-;;;; Property Drawer
-
-(defun org-e-html-property-drawer (property-drawer contents info)
- "Transcode a PROPERTY-DRAWER element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- ;; The property drawer isn't exported but we want separating blank
- ;; lines nonetheless.
- "")
-
-
-;;;; Quote Block
-
-(defun org-e-html-quote-block (quote-block contents info)
- "Transcode a QUOTE-BLOCK element from Org to HTML.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (org-e-html--wrap-label
- quote-block (format "<blockquote>\n%s</blockquote>" contents)))
-
-
-;;;; Quote Section
-
-(defun org-e-html-quote-section (quote-section contents info)
- "Transcode a QUOTE-SECTION element from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((value (org-remove-indentation
- (org-element-property :value quote-section))))
- (when value (format "<pre>\n%s</pre>" value))))
-
-
-;;;; Section
-
-(defun org-e-html-section (section contents info)
- "Transcode a SECTION element from Org to HTML.
-CONTENTS holds the contents of the section. INFO is a plist
-holding contextual information."
- (let ((parent (org-export-get-parent-headline section)))
- ;; Before first headline: no container, just return CONTENTS.
- (if (not parent) contents
- ;; Get div's class and id references.
- (let* ((class-num (+ (org-export-get-relative-level parent info)
- (1- org-e-html-toplevel-hlevel)))
- (section-number
- (mapconcat
- 'number-to-string
- (org-export-get-headline-number parent info) "-")))
- ;; Build return value.
- (format "<div class=\"outline-text-%d\" id=\"text-%s\">\n%s</div>"
- class-num
- (or (org-element-property :custom-id parent) section-number)
- contents)))))
-
-;;;; Radio Target
-
-(defun org-e-html-radio-target (radio-target text info)
- "Transcode a RADIO-TARGET object from Org to HTML.
-TEXT is the text of the target. INFO is a plist holding
-contextual information."
- (let ((id (org-export-solidify-link-text
- (org-element-property :value radio-target))))
- (org-e-html--anchor id text)))
-
-
-;;;; Special Block
-
-(defun org-e-html-special-block (special-block contents info)
- "Transcode a SPECIAL-BLOCK element from Org to HTML.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((type (downcase (org-element-property :type special-block))))
- (org-e-html--wrap-label
- special-block
- (format "<div class=\"%s\">\n%s\n</div>" type contents))))
-
-
-;;;; Src Block
-
-(defun org-e-html-src-block (src-block contents info)
- "Transcode a SRC-BLOCK element from Org to HTML.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((lang (org-element-property :language src-block))
- (caption (org-element-property :caption src-block))
- (label (org-element-property :name src-block))
- (caption-str (org-e-html--caption/label-string caption label info))
- (attr (mapconcat #'identity
- (org-element-property :attr_html src-block)
- " "))
- ;; (switches (org-element-property :switches src-block))
- (switches nil) ; FIXME
- (textarea-p (and switches (string-match "-t\\>" switches)))
- (code (org-e-html-format-code src-block info)))
- (cond
- (lang (format
- "<div class=\"org-src-container\">\n%s%s\n</div>"
- (if (not caption) ""
- (format "<label class=\"org-src-name\">%s</label>" caption-str))
- (format "\n<pre class=\"src src-%s\">%s</pre>" lang code)))
- (textarea-p
- (let ((cols (if (not (string-match "-w[ \t]+\\([0-9]+\\)" switches))
- 80 (string-to-number (match-string 1 switches))))
- (rows (if (string-match "-h[ \t]+\\([0-9]+\\)" switches)
- (string-to-number (match-string 1 switches))
- (org-count-lines code))))
- (format
- "<p>\n<textarea cols=\"%d\" rows=\"%d\">\n%s</textarea>\n</p>"
- cols rows code)))
- (t (format "<pre class=\"example\">\n%s</pre>" code)))))
-
-;;;; Statistics Cookie
-
-(defun org-e-html-statistics-cookie (statistics-cookie contents info)
- "Transcode a STATISTICS-COOKIE object from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((cookie-value (org-element-property :value statistics-cookie)))
- (format "<code>%s</code>" cookie-value)))
-
-
-;;;; Strike-Through
-
-(defun org-e-html-strike-through (strike-through contents info)
- "Transcode STRIKE-THROUGH from Org to HTML.
-CONTENTS is the text with strike-through markup. INFO is a plist
-holding contextual information."
- (format (or (cdr (assq 'strike-through org-e-html-text-markup-alist)) "%s")
- contents))
-
-
-;;;; Subscript
-
-(defun org-e-html-subscript (subscript contents info)
- "Transcode a SUBSCRIPT object from Org to HTML.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "<sub>%s</sub>" contents))
-
-
-;;;; Superscript
-
-(defun org-e-html-superscript (superscript contents info)
- "Transcode a SUPERSCRIPT object from Org to HTML.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "<sup>%s</sup>" contents))
-
-
-;;;; Tabel Cell
-
-(defun org-e-html-table-cell (table-cell contents info)
- "Transcode a TABLE-CELL element from Org to HTML.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (let* ((table-row (org-export-get-parent table-cell))
- (table (org-export-get-parent-table table-cell))
- (cell-attrs
- (if (not org-e-html-table-align-individual-fields) ""
- (format (if (and (boundp 'org-e-html-format-table-no-css)
- org-e-html-format-table-no-css)
- " align=\"%s\"" " class=\"%s\"")
- (org-export-table-cell-alignment table-cell info)))))
- (when (or (not contents) (string= "" (org-trim contents)))
- (setq contents "&nbsp;"))
- (cond
- ((and (org-export-table-has-header-p table info)
- (= 1 (org-export-table-row-group table-row info)))
- (concat "\n" (format (car org-e-html-table-header-tags) "col" cell-attrs)
- contents (cdr org-e-html-table-header-tags)))
- ((and org-e-html-table-use-header-tags-for-first-column
- (zerop (cdr (org-export-table-cell-address table-cell info))))
- (concat "\n" (format (car org-e-html-table-header-tags) "row" cell-attrs)
- contents (cdr org-e-html-table-header-tags)))
- (t (concat "\n" (format (car org-e-html-table-data-tags) cell-attrs)
- contents (cdr org-e-html-table-data-tags))))))
-
-
-;;;; Table Row
-
-(defun org-e-html-table-row (table-row contents info)
- "Transcode a TABLE-ROW element from Org to HTML.
-CONTENTS is the contents of the row. INFO is a plist used as a
-communication channel."
- ;; Rules are ignored since table separators are deduced from
- ;; borders of the current row.
- (when (eq (org-element-property :type table-row) 'standard)
- (let* ((first-rowgroup-p (= 1 (org-export-table-row-group table-row info)))
- (rowgroup-tags
- (cond
- ;; Case 1: Row belongs to second or subsequent rowgroups.
- ((not (= 1 (org-export-table-row-group table-row info)))
- '("<tbody>" . "\n</tbody>"))
- ;; Case 2: Row is from first rowgroup. Table has >=1 rowgroups.
- ((org-export-table-has-header-p
- (org-export-get-parent-table table-row) info)
- '("<thead>" . "\n</thead>"))
- ;; Case 2: Row is from first and only row group.
- (t '("<tbody>" . "\n</tbody>")))))
- (concat
- ;; Begin a rowgroup?
- (when (org-export-table-row-starts-rowgroup-p table-row info)
- (car rowgroup-tags))
- ;; Actual table row
- (concat "\n" (eval (car org-e-html-table-row-tags))
- contents
- "\n"
- (eval (cdr org-e-html-table-row-tags)))
- ;; End a rowgroup?
- (when (org-export-table-row-ends-rowgroup-p table-row info)
- (cdr rowgroup-tags))))))
-
-
-;;;; Table
-
-(defun org-e-html-table-first-row-data-cells (table info)
- (let ((table-row
- (org-element-map
- table 'table-row
- (lambda (row)
- (unless (eq (org-element-property :type row) 'rule) row))
- info 'first-match))
- (special-column-p (org-export-table-has-special-column-p table)))
- (if (not special-column-p) (org-element-contents table-row)
- (cdr (org-element-contents table-row)))))
-
-(defun org-e-html-table--table.el-table (table info)
- (when (eq (org-element-property :type table) 'table.el)
- (require 'table)
- (let ((outbuf (with-current-buffer
- (get-buffer-create "*org-export-table*")
- (erase-buffer) (current-buffer))))
- (with-temp-buffer
- (insert (org-element-property :value table))
- (goto-char 1)
- (re-search-forward "^[ \t]*|[^|]" nil t)
- (table-generate-source 'html outbuf))
- (with-current-buffer outbuf
- (prog1 (org-trim (buffer-string))
- (kill-buffer) )))))
-
-(defun org-e-html-table (table contents info)
- "Transcode a TABLE element from Org to HTML.
-CONTENTS is the contents of the table. INFO is a plist holding
-contextual information."
- (case (org-element-property :type table)
- ;; Case 1: table.el table. Convert it using appropriate tools.
- (table.el (org-e-html-table--table.el-table table info))
- ;; Case 2: Standard table.
- (t
- (let* ((label (org-element-property :name table))
- (caption (org-e-html--caption/label-string
- (org-element-property :caption table) label info))
- (attributes (mapconcat #'identity
- (org-element-property :attr_html table)
- " "))
- (alignspec
- (if (and (boundp 'org-e-html-format-table-no-css)
- org-e-html-format-table-no-css)
- "align=\"%s\"" "class=\"%s\""))
- (table-column-specs
- (function
- (lambda (table info)
- (mapconcat
- (lambda (table-cell)
- (let ((alignment (org-export-table-cell-alignment
- table-cell info)))
- (concat
- ;; Begin a colgroup?
- (when (org-export-table-cell-starts-colgroup-p
- table-cell info)
- "\n<colgroup>")
- ;; Add a column. Also specify it's alignment.
- (format "\n<col %s/>" (format alignspec alignment))
- ;; End a colgroup?
- (when (org-export-table-cell-ends-colgroup-p
- table-cell info)
- "\n</colgroup>"))))
- (org-e-html-table-first-row-data-cells table info) "\n"))))
- (table-attributes
- (let ((table-tag (plist-get info :html-table-tag)))
- (concat
- (and (string-match "<table\\(.*\\)>" table-tag)
- (match-string 1 table-tag))
- (and label (format " id=\"%s\""
- (org-export-solidify-link-text label)))))))
- ;; Remove last blank line.
- (setq contents (substring contents 0 -1))
- (format "<table%s>\n%s\n%s\n%s\n</table>"
- table-attributes
- (if (not caption) "" (format "<caption>%s</caption>" caption))
- (funcall table-column-specs table info)
- contents)))))
-
-;;;; Target
-
-(defun org-e-html-target (target contents info)
- "Transcode a TARGET object from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (let ((id (org-export-solidify-link-text
- (org-element-property :value target))))
- (org-e-html--anchor id)))
-
-
-;;;; Timestamp
-
-(defun org-e-html-timestamp (timestamp contents info)
- "Transcode a TIMESTAMP object from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (let* ((f (if (eq (org-element-property :type timestamp) 'inactive) "[%s]" "<%s>"))
- (value (org-translate-time (format f (org-element-property :value timestamp))))
- (range-end (org-element-property :range-end timestamp)))
- (format "<span class=\"timestamp-wrapper\"><span class=\"timestamp\">%s</span></span>"
- (if (not range-end) value
- (concat value "&ndash;" (org-translate-time (format f range-end)))))))
-
-
-;;;; Underline
-
-(defun org-e-html-underline (underline contents info)
- "Transcode UNDERLINE from Org to HTML.
-CONTENTS is the text with underline markup. INFO is a plist
-holding contextual information."
- (format (or (cdr (assq 'underline org-e-html-text-markup-alist)) "%s")
- contents))
-
-
-;;;; Verbatim
-
-(defun org-e-html-verbatim (verbatim contents info)
- "Transcode VERBATIM from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format (or (cdr (assq 'verbatim org-e-html-text-markup-alist)) "%s")
- (org-element-property :value verbatim)))
-
-
-;;;; Verse Block
-
-(defun org-e-html-verse-block (verse-block contents info)
- "Transcode a VERSE-BLOCK element from Org to HTML.
-CONTENTS is verse block contents. INFO is a plist holding
-contextual information."
- ;; Replace each newline character with line break. Also replace
- ;; each blank line with a line break.
- (setq contents (replace-regexp-in-string
- "^ *\\\\\\\\$" "<br/>\n"
- (replace-regexp-in-string
- "\\(\\\\\\\\\\)?[ \t]*\n" " <br/>\n" contents)))
- ;; Replace each white space at beginning of a line with a
- ;; non-breaking space.
- (while (string-match "^[ \t]+" contents)
- (let* ((num-ws (length (match-string 0 contents)))
- (ws (let (out) (dotimes (i num-ws out)
- (setq out (concat out "&nbsp;"))))))
- (setq contents (replace-match ws nil t contents))))
- (org-e-html--wrap-label
- verse-block (format "<p class=\"verse\">\n%s</p>" contents)))
-
-
-
-
-;;; Filter Functions
-
-(defun org-e-html-final-function (contents backend info)
- (if (not org-e-html-pretty-output) contents
- (with-temp-buffer
- (html-mode)
- (insert contents)
- (indent-region (point-min) (point-max))
- (buffer-substring-no-properties (point-min) (point-max)))))
-
-
-;;; Interactive functions
-
-;;;###autoload
-(defun org-e-html-export-as-html
- (&optional subtreep visible-only body-only ext-plist)
- "Export current buffer to an HTML buffer.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"<body>\" and \"</body>\" tags.
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-Export is done in a buffer named \"*Org E-HTML Export*\", which
-will be displayed when `org-export-show-temporary-export-buffer'
-is non-nil."
- (interactive)
- (let ((outbuf
- (org-export-to-buffer
- 'e-html "*Org E-HTML Export*"
- subtreep visible-only body-only ext-plist)))
- ;; Set major mode.
- (with-current-buffer outbuf (nxml-mode))
- (when org-export-show-temporary-export-buffer
- (switch-to-buffer-other-window outbuf))))
-
-;;;###autoload
-(defun org-e-html-export-to-html
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to a HTML file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"<body>\" and \"</body>\" tags.
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (let* ((extension (concat "." org-e-html-extension))
- (file (org-export-output-file-name extension subtreep pub-dir))
- (org-export-coding-system org-e-html-coding-system))
- (org-export-to-file
- 'e-html file subtreep visible-only body-only ext-plist)))
-
-
-
-;;; FIXME
-
-;;;; org-format-table-html
-;;;; org-format-org-table-html
-;;;; org-format-table-table-html
-;;;; org-table-number-fraction
-;;;; org-table-number-regexp
-;;;; org-e-html-table-caption-above
-
-;;;; org-e-html-with-timestamp
-;;;; org-e-html-html-helper-timestamp
-
-;;;; org-export-as-html-and-open
-;;;; org-export-as-html-batch
-;;;; org-export-as-html-to-buffer
-;;;; org-replace-region-by-html
-;;;; org-export-region-as-html
-;;;; org-export-as-html
-
-;;;; (org-export-directory :html opt-plist)
-;;;; (plist-get opt-plist :html-extension)
-;;;; org-e-html-toplevel-hlevel
-;;;; org-e-html-special-string-regexps
-;;;; org-e-html-inline-images
-;;;; org-e-html-inline-image-extensions
-;;;; org-e-html-protect-char-alist
-;;;; org-e-html-table-use-header-tags-for-first-column
-;;;; org-e-html-todo-kwd-class-prefix
-;;;; org-e-html-tag-class-prefix
-;;;; org-e-html-footnote-separator
-
-;;;; org-export-preferred-target-alist
-;;;; org-export-solidify-link-text
-;;;; class for anchors
-;;;; org-export-with-section-numbers, body-only
-;;;; org-export-mark-todo-in-toc
-
-;;;; org-e-html-format-org-link
-;;;; (caption (and caption (org-xml-encode-org-text caption)))
-;;;; alt = (file-name-nondirectory path)
-
-;;;; org-export-time-stamp-file'
-
-(provide 'org-e-html)
-;;; org-e-html.el ends here
diff --git a/contrib/lisp/org-e-latex.el b/contrib/lisp/org-e-latex.el
deleted file mode 100644
index 8712f5a..0000000
--- a/contrib/lisp/org-e-latex.el
+++ /dev/null
@@ -1,2726 +0,0 @@
-;;; org-e-latex.el --- LaTeX Back-End For Org Export Engine
-
-;; Copyright (C) 2011-2012 Free Software Foundation, Inc.
-
-;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; This library implements a LaTeX back-end for Org generic exporter.
-;;
-;; To test it, run
-;;
-;; M-: (org-export-to-buffer 'e-latex "*Test e-LaTeX*") RET
-;;
-;; in an org-mode buffer then switch to the buffer to see the LaTeX
-;; export. See contrib/lisp/org-export.el for more details on how
-;; this exporter works.
-;;
-;; It introduces three new buffer keywords: "LATEX_CLASS",
-;; "LATEX_CLASS_OPTIONS" and "LATEX_HEADER".
-
-;;; Code:
-
-(eval-when-compile (require 'cl))
-(require 'org-export)
-
-(defvar org-export-latex-default-packages-alist)
-(defvar org-export-latex-packages-alist)
-(defvar orgtbl-exp-regexp)
-
-
-
-;;; Define Back-End
-
-(org-export-define-backend e-latex
- ((bold . org-e-latex-bold)
- (center-block . org-e-latex-center-block)
- (clock . org-e-latex-clock)
- (code . org-e-latex-code)
- (drawer . org-e-latex-drawer)
- (dynamic-block . org-e-latex-dynamic-block)
- (entity . org-e-latex-entity)
- (example-block . org-e-latex-example-block)
- (export-block . org-e-latex-export-block)
- (export-snippet . org-e-latex-export-snippet)
- (fixed-width . org-e-latex-fixed-width)
- (footnote-definition . org-e-latex-footnote-definition)
- (footnote-reference . org-e-latex-footnote-reference)
- (headline . org-e-latex-headline)
- (horizontal-rule . org-e-latex-horizontal-rule)
- (inline-src-block . org-e-latex-inline-src-block)
- (inlinetask . org-e-latex-inlinetask)
- (italic . org-e-latex-italic)
- (item . org-e-latex-item)
- (keyword . org-e-latex-keyword)
- (latex-environment . org-e-latex-latex-environment)
- (latex-fragment . org-e-latex-latex-fragment)
- (line-break . org-e-latex-line-break)
- (link . org-e-latex-link)
- (macro . org-e-latex-macro)
- (paragraph . org-e-latex-paragraph)
- (plain-list . org-e-latex-plain-list)
- (plain-text . org-e-latex-plain-text)
- (planning . org-e-latex-planning)
- (property-drawer . org-e-latex-property-drawer)
- (quote-block . org-e-latex-quote-block)
- (quote-section . org-e-latex-quote-section)
- (radio-target . org-e-latex-radio-target)
- (section . org-e-latex-section)
- (special-block . org-e-latex-special-block)
- (src-block . org-e-latex-src-block)
- (statistics-cookie . org-e-latex-statistics-cookie)
- (strike-through . org-e-latex-strike-through)
- (subscript . org-e-latex-subscript)
- (superscript . org-e-latex-superscript)
- (table . org-e-latex-table)
- (table-cell . org-e-latex-table-cell)
- (table-row . org-e-latex-table-row)
- (target . org-e-latex-target)
- (template . org-e-latex-template)
- (timestamp . org-e-latex-timestamp)
- (underline . org-e-latex-underline)
- (verbatim . org-e-latex-verbatim)
- (verse-block . org-e-latex-verse-block))
- :export-block "LATEX"
- :options-alist ((:date "DATE" nil org-e-latex-date-format t)
- (:latex-class "LATEX_CLASS" nil org-e-latex-default-class t)
- (:latex-class-options "LATEX_CLASS_OPTIONS" nil nil t)
- (:latex-header-extra "LATEX_HEADER" nil nil newline)))
-
-
-
-;;; Internal Variables
-
-(defconst org-e-latex-babel-language-alist
- '(("af" . "afrikaans")
- ("bg" . "bulgarian")
- ("bt-br" . "brazilian")
- ("ca" . "catalan")
- ("cs" . "czech")
- ("cy" . "welsh")
- ("da" . "danish")
- ("de" . "germanb")
- ("de-at" . "naustrian")
- ("de-de" . "ngerman")
- ("el" . "greek")
- ("en" . "english")
- ("en-au" . "australian")
- ("en-ca" . "canadian")
- ("en-gb" . "british")
- ("en-ie" . "irish")
- ("en-nz" . "newzealand")
- ("en-us" . "american")
- ("es" . "spanish")
- ("et" . "estonian")
- ("eu" . "basque")
- ("fi" . "finnish")
- ("fr" . "frenchb")
- ("fr-ca" . "canadien")
- ("gl" . "galician")
- ("hr" . "croatian")
- ("hu" . "hungarian")
- ("id" . "indonesian")
- ("is" . "icelandic")
- ("it" . "italian")
- ("la" . "latin")
- ("ms" . "malay")
- ("nl" . "dutch")
- ("no-no" . "nynorsk")
- ("pl" . "polish")
- ("pt" . "portuguese")
- ("ro" . "romanian")
- ("ru" . "russian")
- ("sa" . "sanskrit")
- ("sb" . "uppersorbian")
- ("sk" . "slovak")
- ("sl" . "slovene")
- ("sq" . "albanian")
- ("sr" . "serbian")
- ("sv" . "swedish")
- ("ta" . "tamil")
- ("tr" . "turkish")
- ("uk" . "ukrainian"))
- "Alist between language code and corresponding Babel option.")
-
-
-
-;;; User Configurable Variables
-
-(defgroup org-export-e-latex nil
- "Options for exporting Org mode files to LaTeX."
- :tag "Org Export LaTeX"
- :group 'org-export)
-
-
-;;;; Preamble
-
-(defcustom org-e-latex-default-class "article"
- "The default LaTeX class."
- :group 'org-export-e-latex
- :type '(string :tag "LaTeX class"))
-
-(defcustom org-e-latex-classes
- '(("article"
- "\\documentclass[11pt]{article}"
- ("\\section{%s}" . "\\section*{%s}")
- ("\\subsection{%s}" . "\\subsection*{%s}")
- ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
- ("\\paragraph{%s}" . "\\paragraph*{%s}")
- ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
- ("report"
- "\\documentclass[11pt]{report}"
- ("\\part{%s}" . "\\part*{%s}")
- ("\\chapter{%s}" . "\\chapter*{%s}")
- ("\\section{%s}" . "\\section*{%s}")
- ("\\subsection{%s}" . "\\subsection*{%s}")
- ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
- ("book"
- "\\documentclass[11pt]{book}"
- ("\\part{%s}" . "\\part*{%s}")
- ("\\chapter{%s}" . "\\chapter*{%s}")
- ("\\section{%s}" . "\\section*{%s}")
- ("\\subsection{%s}" . "\\subsection*{%s}")
- ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
- "Alist of LaTeX classes and associated header and structure.
-If #+LaTeX_CLASS is set in the buffer, use its value and the
-associated information. Here is the structure of each cell:
-
- \(class-name
- header-string
- \(numbered-section . unnumbered-section\)
- ...\)
-
-The header string
------------------
-
-The HEADER-STRING is the header that will be inserted into the
-LaTeX file. It should contain the \\documentclass macro, and
-anything else that is needed for this setup. To this header, the
-following commands will be added:
-
-- Calls to \\usepackage for all packages mentioned in the
- variables `org-export-latex-default-packages-alist' and
- `org-export-latex-packages-alist'. Thus, your header
- definitions should avoid to also request these packages.
-
-- Lines specified via \"#+LaTeX_HEADER:\"
-
-If you need more control about the sequence in which the header
-is built up, or if you want to exclude one of these building
-blocks for a particular class, you can use the following
-macro-like placeholders.
-
- [DEFAULT-PACKAGES] \\usepackage statements for default packages
- [NO-DEFAULT-PACKAGES] do not include any of the default packages
- [PACKAGES] \\usepackage statements for packages
- [NO-PACKAGES] do not include the packages
- [EXTRA] the stuff from #+LaTeX_HEADER
- [NO-EXTRA] do not include #+LaTeX_HEADER stuff
-
-So a header like
-
- \\documentclass{article}
- [NO-DEFAULT-PACKAGES]
- [EXTRA]
- \\providecommand{\\alert}[1]{\\textbf{#1}}
- [PACKAGES]
-
-will omit the default packages, and will include the
-#+LaTeX_HEADER lines, then have a call to \\providecommand, and
-then place \\usepackage commands based on the content of
-`org-export-latex-packages-alist'.
-
-If your header, `org-export-latex-default-packages-alist' or
-`org-export-latex-packages-alist' inserts
-\"\\usepackage[AUTO]{inputenc}\", AUTO will automatically be
-replaced with a coding system derived from
-`buffer-file-coding-system'. See also the variable
-`org-e-latex-inputenc-alist' for a way to influence this
-mechanism.
-
-The sectioning structure
-------------------------
-
-The sectioning structure of the class is given by the elements
-following the header string. For each sectioning level, a number
-of strings is specified. A %s formatter is mandatory in each
-section string and will be replaced by the title of the section.
-
-Instead of a cons cell \(numbered . unnumbered\), you can also
-provide a list of 2 or 4 elements,
-
- \(numbered-open numbered-close\)
-
-or
-
- \(numbered-open numbered-close unnumbered-open unnumbered-close\)
-
-providing opening and closing strings for a LaTeX environment
-that should represent the document section. The opening clause
-should have a %s to represent the section title.
-
-Instead of a list of sectioning commands, you can also specify
-a function name. That function will be called with two
-parameters, the \(reduced) level of the headline, and a predicate
-non-nil when the headline should be numbered. It must return
-a format string in which the section title will be added."
- :group 'org-export-e-latex
- :type '(repeat
- (list (string :tag "LaTeX class")
- (string :tag "LaTeX header")
- (repeat :tag "Levels" :inline t
- (choice
- (cons :tag "Heading"
- (string :tag " numbered")
- (string :tag "unnumbered"))
- (list :tag "Environment"
- (string :tag "Opening (numbered)")
- (string :tag "Closing (numbered)")
- (string :tag "Opening (unnumbered)")
- (string :tag "Closing (unnumbered)"))
- (function :tag "Hook computing sectioning"))))))
-
-(defcustom org-e-latex-inputenc-alist nil
- "Alist of inputenc coding system names, and what should really be used.
-For example, adding an entry
-
- (\"utf8\" . \"utf8x\")
-
-will cause \\usepackage[utf8x]{inputenc} to be used for buffers that
-are written as utf8 files."
- :group 'org-export-e-latex
- :type '(repeat
- (cons
- (string :tag "Derived from buffer")
- (string :tag "Use this instead"))))
-
-(defcustom org-e-latex-date-format
- "\\today"
- "Format string for \\date{...}."
- :group 'org-export-e-latex
- :type 'boolean)
-
-(defcustom org-e-latex-title-command "\\maketitle"
- "The command used to insert the title just after \\begin{document}.
-If this string contains the formatting specification \"%s\" then
-it will be used as a formatting string, passing the title as an
-argument."
- :group 'org-export-e-latex
- :type 'string)
-
-
-;;;; Headline
-
-(defcustom org-e-latex-format-headline-function nil
- "Function to format headline text.
-
-This function will be called with 5 arguments:
-TODO the todo keyword (string or nil).
-TODO-TYPE the type of todo (symbol: `todo', `done', nil)
-PRIORITY the priority of the headline (integer or nil)
-TEXT the main headline text (string).
-TAGS the tags as a list of strings (list of strings or nil).
-
-The function result will be used in the section format string.
-
-As an example, one could set the variable to the following, in
-order to reproduce the default set-up:
-
-\(defun org-e-latex-format-headline (todo todo-type priority text tags)
- \"Default format function for an headline.\"
- \(concat (when todo
- \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo))
- \(when priority
- \(format \"\\\\framebox{\\\\#%c} \" priority))
- text
- \(when tags
- \(format \"\\\\hfill{}\\\\textsc{%s}\"
- \(mapconcat 'identity tags \":\"))))"
- :group 'org-export-e-latex
- :type 'function)
-
-
-;;;; Footnotes
-
-(defcustom org-e-latex-footnote-separator "\\textsuperscript{,}\\,"
- "Text used to separate footnotes."
- :group 'org-export-e-latex
- :type 'string)
-
-
-;;;; Timestamps
-
-(defcustom org-e-latex-active-timestamp-format "\\textit{%s}"
- "A printf format string to be applied to active timestamps."
- :group 'org-export-e-latex
- :type 'string)
-
-(defcustom org-e-latex-inactive-timestamp-format "\\textit{%s}"
- "A printf format string to be applied to inactive timestamps."
- :group 'org-export-e-latex
- :type 'string)
-
-(defcustom org-e-latex-diary-timestamp-format "\\textit{%s}"
- "A printf format string to be applied to diary timestamps."
- :group 'org-export-e-latex
- :type 'string)
-
-
-;;;; Links
-
-(defcustom org-e-latex-image-default-option "width=.9\\linewidth"
- "Default option for images."
- :group 'org-export-e-latex
- :type 'string)
-
-(defcustom org-e-latex-default-figure-position "htb"
- "Default position for latex figures."
- :group 'org-export-e-latex
- :type 'string)
-
-(defcustom org-e-latex-inline-image-rules
- '(("file" . "\\.\\(pdf\\|jpeg\\|jpg\\|png\\|ps\\|eps\\)\\'"))
- "Rules characterizing image files that can be inlined into LaTeX.
-
-A rule consists in an association whose key is the type of link
-to consider, and value is a regexp that will be matched against
-link's path.
-
-Note that, by default, the image extension *actually* allowed
-depend on the way the LaTeX file is processed. When used with
-pdflatex, pdf, jpg and png images are OK. When processing
-through dvi to Postscript, only ps and eps are allowed. The
-default we use here encompasses both."
- :group 'org-export-e-latex
- :type '(alist :key-type (string :tag "Type")
- :value-type (regexp :tag "Path")))
-
-(defcustom org-e-latex-link-with-unknown-path-format "\\texttt{%s}"
- "Format string for links with unknown path type."
- :group 'org-export-latex
- :type 'string)
-
-
-;;;; Tables
-
-(defcustom org-e-latex-default-table-environment "tabular"
- "Default environment used to build tables."
- :group 'org-export-e-latex
- :type 'string)
-
-(defcustom org-e-latex-tables-centered t
- "When non-nil, tables are exported in a center environment."
- :group 'org-export-e-latex
- :type 'boolean)
-
-(defcustom org-e-latex-tables-verbatim nil
- "When non-nil, tables are exported verbatim."
- :group 'org-export-e-latex
- :type 'boolean)
-
-(defcustom org-e-latex-tables-booktabs nil
- "When non-nil, display tables in a formal \"booktabs\" style.
-This option assumes that the \"booktabs\" package is properly
-loaded in the header of the document. This value can be ignored
-locally with \"booktabs=yes\" and \"booktabs=no\" LaTeX
-attributes."
- :group 'org-export-e-latex
- :type 'boolean)
-
-(defcustom org-e-latex-table-caption-above t
- "When non-nil, place caption string at the beginning of the table.
-Otherwise, place it near the end."
- :group 'org-export-e-latex
- :type 'boolean)
-
-(defcustom org-e-latex-table-scientific-notation "%s\\,(%s)"
- "Format string to display numbers in scientific notation.
-The format should have \"%s\" twice, for mantissa and exponent
-\(i.e. \"%s\\\\times10^{%s}\").
-
-When nil, no transformation is made."
- :group 'org-export-e-latex
- :type '(choice
- (string :tag "Format string")
- (const :tag "No formatting")))
-
-
-;;;; Text markup
-
-(defcustom org-e-latex-text-markup-alist '((bold . "\\textbf{%s}")
- (code . verb)
- (italic . "\\emph{%s}")
- (strike-through . "\\st{%s}")
- (underline . "\\underline{%s}")
- (verbatim . protectedtexttt))
- "Alist of LaTeX expressions to convert text markup.
-
-The key must be a symbol among `bold', `code', `italic',
-`strike-through', `underline' and `verbatim'. The value is
-a formatting string to wrap fontified text with.
-
-Value can also be set to the following symbols: `verb' and
-`protectedtexttt'. For the former, Org will use \"\\verb\" to
-create a format string and select a delimiter character that
-isn't in the string. For the latter, Org will use \"\\texttt\"
-to typeset and try to protect special characters.
-
-If no association can be found for a given markup, text will be
-returned as-is."
- :group 'org-export-e-latex
- :type 'alist
- :options '(bold code italic strike-through underline verbatim))
-
-
-;;;; Drawers
-
-(defcustom org-e-latex-format-drawer-function nil
- "Function called to format a drawer in LaTeX code.
-
-The function must accept two parameters:
- NAME the drawer name, like \"LOGBOOK\"
- CONTENTS the contents of the drawer.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-latex-format-drawer-default \(name contents\)
- \"Format a drawer element for LaTeX export.\"
- contents\)"
- :group 'org-export-e-latex
- :type 'function)
-
-
-;;;; Inlinetasks
-
-(defcustom org-e-latex-format-inlinetask-function nil
- "Function called to format an inlinetask in LaTeX code.
-
-The function must accept six parameters:
- TODO the todo keyword, as a string
- TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
- PRIORITY the inlinetask priority, as a string
- NAME the inlinetask name, as a string.
- TAGS the inlinetask tags, as a list of strings.
- CONTENTS the contents of the inlinetask, as a string.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-latex-format-inlinetask \(todo type priority name tags contents\)
-\"Format an inline task element for LaTeX export.\"
- \(let ((full-title
- \(concat
- \(when todo
- \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo))
- \(when priority (format \"\\\\framebox{\\\\#%c} \" priority))
- title
- \(when tags
- \(format \"\\\\hfill{}\\\\textsc{:%s:}\"
- \(mapconcat 'identity tags \":\")))))
- \(format (concat \"\\\\begin{center}\\n\"
- \"\\\\fbox{\\n\"
- \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
- \"%s\\n\\n\"
- \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
- \"%s\"
- \"\\\\end{minipage}}\"
- \"\\\\end{center}\")
- full-title contents))"
- :group 'org-export-e-latex
- :type 'function)
-
-
-;; Src blocks
-
-(defcustom org-e-latex-listings nil
- "Non-nil means export source code using the listings package.
-This package will fontify source code, possibly even with color.
-If you want to use this, you also need to make LaTeX use the
-listings package, and if you want to have color, the color
-package. Just add these to `org-export-latex-packages-alist',
-for example using customize, or with something like:
-
- \(require 'org-e-latex)
- \(add-to-list 'org-export-latex-packages-alist '\(\"\" \"listings\"))
- \(add-to-list 'org-export-latex-packages-alist '\(\"\" \"color\"))
-
-Alternatively,
-
- \(setq org-e-latex-listings 'minted)
-
-causes source code to be exported using the minted package as
-opposed to listings. If you want to use minted, you need to add
-the minted package to `org-export-latex-packages-alist', for
-example using customize, or with
-
- \(require 'org-e-latex)
- \(add-to-list 'org-export-latex-packages-alist '\(\"\" \"minted\"))
-
-In addition, it is necessary to install pygments
-\(http://pygments.org), and to configure the variable
-`org-e-latex-pdf-process' so that the -shell-escape option is
-passed to pdflatex."
- :group 'org-export-e-latex
- :type '(choice
- (const :tag "Use listings" t)
- (const :tag "Use minted" 'minted)
- (const :tag "Export verbatim" nil)))
-
-(defcustom org-e-latex-listings-langs
- '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp")
- (c "C") (cc "C++")
- (fortran "fortran")
- (perl "Perl") (cperl "Perl") (python "Python") (ruby "Ruby")
- (html "HTML") (xml "XML")
- (tex "TeX") (latex "TeX")
- (shell-script "bash")
- (gnuplot "Gnuplot")
- (ocaml "Caml") (caml "Caml")
- (sql "SQL") (sqlite "sql"))
- "Alist mapping languages to their listing language counterpart.
-The key is a symbol, the major mode symbol without the \"-mode\".
-The value is the string that should be inserted as the language
-parameter for the listings package. If the mode name and the
-listings name are the same, the language does not need an entry
-in this list - but it does not hurt if it is present."
- :group 'org-export-e-latex
- :type '(repeat
- (list
- (symbol :tag "Major mode ")
- (string :tag "Listings language"))))
-
-(defcustom org-e-latex-listings-options nil
- "Association list of options for the latex listings package.
-
-These options are supplied as a comma-separated list to the
-\\lstset command. Each element of the association list should be
-a list containing two strings: the name of the option, and the
-value. For example,
-
- (setq org-e-latex-listings-options
- '((\"basicstyle\" \"\\small\")
- (\"keywordstyle\" \"\\color{black}\\bfseries\\underbar\")))
-
-will typeset the code in a small size font with underlined, bold
-black keywords.
-
-Note that the same options will be applied to blocks of all
-languages."
- :group 'org-export-e-latex
- :type '(repeat
- (list
- (string :tag "Listings option name ")
- (string :tag "Listings option value"))))
-
-(defcustom org-e-latex-minted-langs
- '((emacs-lisp "common-lisp")
- (cc "c++")
- (cperl "perl")
- (shell-script "bash")
- (caml "ocaml"))
- "Alist mapping languages to their minted language counterpart.
-The key is a symbol, the major mode symbol without the \"-mode\".
-The value is the string that should be inserted as the language
-parameter for the minted package. If the mode name and the
-listings name are the same, the language does not need an entry
-in this list - but it does not hurt if it is present.
-
-Note that minted uses all lower case for language identifiers,
-and that the full list of language identifiers can be obtained
-with:
-
- pygmentize -L lexers"
- :group 'org-export-e-latex
- :type '(repeat
- (list
- (symbol :tag "Major mode ")
- (string :tag "Minted language"))))
-
-(defcustom org-e-latex-minted-options nil
- "Association list of options for the latex minted package.
-
-These options are supplied within square brackets in
-\\begin{minted} environments. Each element of the alist should
-be a list containing two strings: the name of the option, and the
-value. For example,
-
- \(setq org-e-latex-minted-options
- '\((\"bgcolor\" \"bg\") \(\"frame\" \"lines\")))
-
-will result in src blocks being exported with
-
-\\begin{minted}[bgcolor=bg,frame=lines]{<LANG>}
-
-as the start of the minted environment. Note that the same
-options will be applied to blocks of all languages."
- :group 'org-export-e-latex
- :type '(repeat
- (list
- (string :tag "Minted option name ")
- (string :tag "Minted option value"))))
-
-(defvar org-e-latex-custom-lang-environments nil
- "Alist mapping languages to language-specific LaTeX environments.
-
-It is used during export of src blocks by the listings and minted
-latex packages. For example,
-
- \(setq org-e-latex-custom-lang-environments
- '\(\(python \"pythoncode\"\)\)\)
-
-would have the effect that if org encounters begin_src python
-during latex export it will output
-
- \\begin{pythoncode}
- <src block body>
- \\end{pythoncode}")
-
-
-;;;; Plain text
-
-(defcustom org-e-latex-quotes
- '(("fr"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "«~")
- ("\\(\\S-\\)\"" . "~»")
- ("\\(\\s-\\|(\\|^\\)'" . "'"))
- ("en"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "``")
- ("\\(\\S-\\)\"" . "''")
- ("\\(\\s-\\|(\\|^\\)'" . "`")))
- "Alist for quotes to use when converting english double-quotes.
-
-The CAR of each item in this alist is the language code.
-The CDR of each item in this alist is a list of three CONS:
-- the first CONS defines the opening quote;
-- the second CONS defines the closing quote;
-- the last CONS defines single quotes.
-
-For each item in a CONS, the first string is a regexp
-for allowed characters before/after the quote, the second
-string defines the replacement string for this quote."
- :group 'org-export-e-latex
- :type '(list
- (cons :tag "Opening quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))
- (cons :tag "Closing quote"
- (string :tag "Regexp for char after ")
- (string :tag "Replacement quote "))
- (cons :tag "Single quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))))
-
-
-;;;; Compilation
-
-(defcustom org-e-latex-pdf-process
- '("pdflatex -interaction nonstopmode -output-directory %o %f"
- "pdflatex -interaction nonstopmode -output-directory %o %f"
- "pdflatex -interaction nonstopmode -output-directory %o %f")
- "Commands to process a LaTeX file to a PDF file.
-This is a list of strings, each of them will be given to the
-shell as a command. %f in the command will be replaced by the
-full file name, %b by the file base name \(i.e. without
-extension) and %o by the base directory of the file.
-
-The reason why this is a list is that it usually takes several
-runs of `pdflatex', maybe mixed with a call to `bibtex'. Org
-does not have a clever mechanism to detect which of these
-commands have to be run to get to a stable result, and it also
-does not do any error checking.
-
-By default, Org uses 3 runs of `pdflatex' to do the processing.
-If you have texi2dvi on your system and if that does not cause
-the infamous egrep/locale bug:
-
- http://lists.gnu.org/archive/html/bug-texinfo/2010-03/msg00031.html
-
-then `texi2dvi' is the superior choice. Org does offer it as one
-of the customize options.
-
-Alternatively, this may be a Lisp function that does the
-processing, so you could use this to apply the machinery of
-AUCTeX or the Emacs LaTeX mode. This function should accept the
-file name as its single argument."
- :group 'org-export-pdf
- :type '(choice
- (repeat :tag "Shell command sequence"
- (string :tag "Shell command"))
- (const :tag "2 runs of pdflatex"
- ("pdflatex -interaction nonstopmode -output-directory %o %f"
- "pdflatex -interaction nonstopmode -output-directory %o %f"))
- (const :tag "3 runs of pdflatex"
- ("pdflatex -interaction nonstopmode -output-directory %o %f"
- "pdflatex -interaction nonstopmode -output-directory %o %f"
- "pdflatex -interaction nonstopmode -output-directory %o %f"))
- (const :tag "pdflatex,bibtex,pdflatex,pdflatex"
- ("pdflatex -interaction nonstopmode -output-directory %o %f"
- "bibtex %b"
- "pdflatex -interaction nonstopmode -output-directory %o %f"
- "pdflatex -interaction nonstopmode -output-directory %o %f"))
- (const :tag "texi2dvi"
- ("texi2dvi -p -b -c -V %f"))
- (const :tag "rubber"
- ("rubber -d --into %o %f"))
- (function)))
-
-(defcustom org-e-latex-logfiles-extensions
- '("aux" "idx" "log" "out" "toc" "nav" "snm" "vrb")
- "The list of file extensions to consider as LaTeX logfiles."
- :group 'org-export-e-latex
- :type '(repeat (string :tag "Extension")))
-
-(defcustom org-e-latex-remove-logfiles t
- "Non-nil means remove the logfiles produced by PDF production.
-These are the .aux, .log, .out, and .toc files."
- :group 'org-export-e-latex
- :type 'boolean)
-
-
-
-;;; Internal Functions
-
-(defun org-e-latex--caption/label-string (caption label info)
- "Return caption and label LaTeX string for floats.
-
-CAPTION is a cons cell of secondary strings, the car being the
-standard caption and the cdr its short form. LABEL is a string
-representing the label. INFO is a plist holding contextual
-information.
-
-If there's no caption nor label, return the empty string.
-
-For non-floats, see `org-e-latex--wrap-label'."
- (let ((label-str (if label (format "\\label{%s}" label) "")))
- (cond
- ((and (not caption) (not label)) "")
- ((not caption) (format "\\label{%s}\n" label))
- ;; Option caption format with short name.
- ((cdr caption)
- (format "\\caption[%s]{%s%s}\n"
- (org-export-data (cdr caption) info)
- label-str
- (org-export-data (car caption) info)))
- ;; Standard caption format.
- (t (format "\\caption{%s%s}\n"
- label-str
- (org-export-data (car caption) info))))))
-
-(defun org-e-latex--guess-babel-language (header info)
- "Set Babel's language according to LANGUAGE keyword.
-
-HEADER is the LaTeX header string. INFO is the plist used as
-a communication channel.
-
-Insertion of guessed language only happens when Babel package has
-explicitly been loaded. Then it is added to the rest of
-package's options.
-
-Return the new header."
- (let ((language-code (plist-get info :language)))
- ;; If no language is set or Babel package is not loaded, return
- ;; HEADER as-is.
- (if (or (not (stringp language-code))
- (not (string-match "\\\\usepackage\\[\\(.*\\)\\]{babel}" header)))
- header
- (let ((options (save-match-data
- (org-split-string (match-string 1 header) ",")))
- (language (cdr (assoc language-code
- org-e-latex-babel-language-alist))))
- ;; If LANGUAGE is already loaded, return header. Otherwise,
- ;; append LANGUAGE to other options.
- (if (member language options) header
- (replace-match (mapconcat 'identity
- (append options (list language))
- ",")
- nil nil header 1))))))
-
-(defun org-e-latex--guess-inputenc (header)
- "Set the coding system in inputenc to what the buffer is.
-HEADER is the LaTeX header string. Return the new header."
- (let* ((cs (or (ignore-errors
- (latexenc-coding-system-to-inputenc
- buffer-file-coding-system))
- "utf8")))
- (if (not cs) header
- ;; First translate if that is requested.
- (setq cs (or (cdr (assoc cs org-e-latex-inputenc-alist)) cs))
- ;; Then find the \usepackage statement and replace the option.
- (replace-regexp-in-string "\\\\usepackage\\[\\(AUTO\\)\\]{inputenc}"
- cs header t nil 1))))
-
-(defun org-e-latex--find-verb-separator (s)
- "Return a character not used in string S.
-This is used to choose a separator for constructs like \\verb."
- (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
- (loop for c across ll
- when (not (string-match (regexp-quote (char-to-string c)) s))
- return (char-to-string c))))
-
-(defun org-e-latex--make-option-string (options)
- "Return a comma separated string of keywords and values.
-OPTIONS is an alist where the key is the options keyword as
-a string, and the value a list containing the keyword value, or
-nil."
- (mapconcat (lambda (pair)
- (concat (first pair)
- (when (> (length (second pair)) 0)
- (concat "=" (second pair)))))
- options
- ","))
-
-(defun org-e-latex--quotation-marks (text info)
- "Export quotation marks depending on language conventions.
-TEXT is a string containing quotation marks to be replaced. INFO
-is a plist used as a communication channel."
- (mapc (lambda(l)
- (let ((start 0))
- (while (setq start (string-match (car l) text start))
- (let ((new-quote (concat (match-string 1 text) (cdr l))))
- (setq text (replace-match new-quote t t text))))))
- (cdr (or (assoc (plist-get info :language) org-e-latex-quotes)
- ;; Falls back on English.
- (assoc "en" org-e-latex-quotes))))
- text)
-
-(defun org-e-latex--wrap-label (element output)
- "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
-This function shouldn't be used for floats. See
-`org-e-latex--caption/label-string'."
- (let ((label (org-element-property :name element)))
- (if (or (not output) (not label) (string= output "") (string= label ""))
- output
- (concat (format "\\label{%s}\n" label) output))))
-
-(defun org-e-latex--text-markup (text markup)
- "Format TEXT depending on MARKUP text markup.
-See `org-e-latex-text-markup-alist' for details."
- (let ((fmt (cdr (assq markup org-e-latex-text-markup-alist))))
- (cond
- ;; No format string: Return raw text.
- ((not fmt) text)
- ;; Handle the `verb' special case: Find and appropriate separator
- ;; and use "\\verb" command.
- ((eq 'verb fmt)
- (let ((separator (org-e-latex--find-verb-separator text)))
- (concat "\\verb" separator text separator)))
- ;; Handle the `protectedtexttt' special case: Protect some
- ;; special chars and use "\texttt{%s}" format string.
- ((eq 'protectedtexttt fmt)
- (let ((start 0)
- (trans '(("\\" . "\\textbackslash{}")
- ("~" . "\\textasciitilde{}")
- ("^" . "\\textasciicircum{}")))
- (rtn "")
- char)
- (while (string-match "[\\{}$%&_#~^]" text)
- (setq char (match-string 0 text))
- (if (> (match-beginning 0) 0)
- (setq rtn (concat rtn (substring text 0 (match-beginning 0)))))
- (setq text (substring text (1+ (match-beginning 0))))
- (setq char (or (cdr (assoc char trans)) (concat "\\" char))
- rtn (concat rtn char)))
- (setq text (concat rtn text)
- fmt "\\texttt{%s}")
- (while (string-match "--" text)
- (setq text (replace-match "-{}-" t t text)))
- (format fmt text)))
- ;; Else use format string.
- (t (format fmt text)))))
-
-(defun org-e-latex--delayed-footnotes-definitions (element info)
- "Return footnotes definitions in ELEMENT as a string.
-
-INFO is a plist used as a communication channel.
-
-Footnotes definitions are returned within \"\\footnotetxt{}\"
-commands.
-
-This function is used within constructs that don't support
-\"\\footnote{}\" command (i.e. an item's tag). In that case,
-\"\\footnotemark\" is used within the construct and the function
-just outside of it."
- (mapconcat
- (lambda (ref)
- (format
- "\\footnotetext[%s]{%s}"
- (org-export-get-footnote-number ref info)
- (org-trim
- (org-export-data
- (org-export-get-footnote-definition ref info) info))))
- ;; Find every footnote reference in ELEMENT.
- (let* (all-refs
- search-refs ; For byte-compiler.
- (search-refs
- (function
- (lambda (data)
- ;; Return a list of all footnote references never seen
- ;; before in DATA.
- (org-element-map
- data 'footnote-reference
- (lambda (ref)
- (when (org-export-footnote-first-reference-p ref info)
- (push ref all-refs)
- (when (eq (org-element-property :type ref) 'standard)
- (funcall search-refs
- (org-export-get-footnote-definition ref info)))))
- info)
- (reverse all-refs)))))
- (funcall search-refs element))
- ""))
-
-
-
-;;; Template
-
-(defun org-e-latex-template (contents info)
- "Return complete document string after LaTeX conversion.
-CONTENTS is the transcoded contents string. INFO is a plist
-holding export options."
- (let ((title (org-export-data (plist-get info :title) info)))
- (concat
- ;; Time-stamp.
- (and (plist-get info :time-stamp-file)
- (format-time-string "%% Created %Y-%m-%d %a %H:%M\n"))
- ;; Document class and packages.
- (let ((class (plist-get info :latex-class))
- (class-options (plist-get info :latex-class-options)))
- (org-element-normalize-string
- (let* ((header (nth 1 (assoc class org-e-latex-classes)))
- (document-class-string
- (and (stringp header)
- (if class-options
- (replace-regexp-in-string
- "^[ \t]*\\\\documentclass\\(\\[.*?\\]\\)"
- class-options header t nil 1)
- header))))
- (when document-class-string
- (org-e-latex--guess-babel-language
- (org-e-latex--guess-inputenc
- (org-splice-latex-header
- document-class-string
- org-export-latex-default-packages-alist ; defined in org.el
- org-export-latex-packages-alist nil ; defined in org.el
- (plist-get info :latex-header-extra)))
- info)))))
- ;; Possibly limit depth for headline numbering.
- (let ((sec-num (plist-get info :section-numbers)))
- (when (integerp sec-num)
- (format "\\setcounter{secnumdepth}{%d}\n" sec-num)))
- ;; Author.
- (let ((author (and (plist-get info :with-author)
- (let ((auth (plist-get info :author)))
- (and auth (org-export-data auth info)))))
- (email (and (plist-get info :with-email)
- (org-export-data (plist-get info :email) info))))
- (cond ((and author email (not (string= "" email)))
- (format "\\author{%s\\thanks{%s}}\n" author email))
- (author (format "\\author{%s}\n" author))
- (t "\\author{}\n")))
- ;; Date.
- (let ((date (org-export-data (plist-get info :date) info)))
- (and date (format "\\date{%s}\n" date)))
- ;; Title
- (format "\\title{%s}\n" title)
- ;; Hyperref options.
- (format "\\hypersetup{\n pdfkeywords={%s},\n pdfsubject={%s},\n pdfcreator={%s}}\n"
- (or (plist-get info :keywords) "")
- (or (plist-get info :description) "")
- (if (not (plist-get info :with-creator)) ""
- (plist-get info :creator)))
- ;; Document start.
- "\\begin{document}\n\n"
- ;; Title command.
- (org-element-normalize-string
- (cond ((string= "" title) nil)
- ((not (stringp org-e-latex-title-command)) nil)
- ((string-match "\\(?:[^%]\\|^\\)%s"
- org-e-latex-title-command)
- (format org-e-latex-title-command title))
- (t org-e-latex-title-command)))
- ;; Table of contents.
- (let ((depth (plist-get info :with-toc)))
- (when depth
- (concat (when (wholenump depth)
- (format "\\setcounter{tocdepth}{%d}\n" depth))
- "\\tableofcontents\n\\vspace*{1cm}\n\n")))
- ;; Document's body.
- contents
- ;; Creator.
- (let ((creator-info (plist-get info :with-creator)))
- (cond
- ((not creator-info) "")
- ((eq creator-info 'comment)
- (format "%% %s\n" (plist-get info :creator)))
- (t (concat (plist-get info :creator) "\n"))))
- ;; Document end.
- "\\end{document}")))
-
-
-
-;;; Transcode Functions
-
-;;;; Babel Call
-;;
-;; Babel Calls are ignored.
-
-
-;;;; Bold
-
-(defun org-e-latex-bold (bold contents info)
- "Transcode BOLD from Org to LaTeX.
-CONTENTS is the text with bold markup. INFO is a plist holding
-contextual information."
- (org-e-latex--text-markup contents 'bold))
-
-
-;;;; Center Block
-
-(defun org-e-latex-center-block (center-block contents info)
- "Transcode a CENTER-BLOCK element from Org to LaTeX.
-CONTENTS holds the contents of the center block. INFO is a plist
-holding contextual information."
- (org-e-latex--wrap-label
- center-block
- (format "\\begin{center}\n%s\\end{center}" contents)))
-
-
-;;;; Clock
-
-(defun org-e-latex-clock (clock contents info)
- "Transcode a CLOCK element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (concat
- "\\noindent"
- (format "\\textbf{%s} " org-clock-string)
- (format org-e-latex-inactive-timestamp-format
- (concat (org-translate-time (org-element-property :value clock))
- (let ((time (org-element-property :time clock)))
- (and time (format " (%s)" time)))))
- "\\\\"))
-
-
-;;;; Code
-
-(defun org-e-latex-code (code contents info)
- "Transcode a CODE object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (org-e-latex--text-markup (org-element-property :value code) 'code))
-
-
-;;;; Comment
-;;
-;; Comments are ignored.
-
-
-;;;; Comment Block
-;;
-;; Comment Blocks are ignored.
-
-
-;;;; Drawer
-
-(defun org-e-latex-drawer (drawer contents info)
- "Transcode a DRAWER element from Org to LaTeX.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let* ((name (org-element-property :drawer-name drawer))
- (output (if (functionp org-e-latex-format-drawer-function)
- (funcall org-e-latex-format-drawer-function
- name contents)
- ;; If there's no user defined function: simply
- ;; display contents of the drawer.
- contents)))
- (org-e-latex--wrap-label drawer output)))
-
-
-;;;; Dynamic Block
-
-(defun org-e-latex-dynamic-block (dynamic-block contents info)
- "Transcode a DYNAMIC-BLOCK element from Org to LaTeX.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information. See `org-export-data'."
- (org-e-latex--wrap-label dynamic-block contents))
-
-
-;;;; Entity
-
-(defun org-e-latex-entity (entity contents info)
- "Transcode an ENTITY object from Org to LaTeX.
-CONTENTS are the definition itself. INFO is a plist holding
-contextual information."
- (let ((ent (org-element-property :latex entity)))
- (if (org-element-property :latex-math-p entity) (format "$%s$" ent) ent)))
-
-
-;;;; Example Block
-
-(defun org-e-latex-example-block (example-block contents info)
- "Transcode an EXAMPLE-BLOCK element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (org-e-latex--wrap-label
- example-block
- (format "\\begin{verbatim}\n%s\\end{verbatim}"
- (org-export-format-code-default example-block info))))
-
-
-;;;; Export Block
-
-(defun org-e-latex-export-block (export-block contents info)
- "Transcode a EXPORT-BLOCK element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (string= (org-element-property :type export-block) "LATEX")
- (org-remove-indentation (org-element-property :value export-block))))
-
-
-;;;; Export Snippet
-
-(defun org-e-latex-export-snippet (export-snippet contents info)
- "Transcode a EXPORT-SNIPPET object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (eq (org-export-snippet-backend export-snippet) 'e-latex)
- (org-element-property :value export-snippet)))
-
-
-;;;; Fixed Width
-
-(defun org-e-latex-fixed-width (fixed-width contents info)
- "Transcode a FIXED-WIDTH element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-latex--wrap-label
- fixed-width
- (format "\\begin{verbatim}\n%s\\end{verbatim}"
- (org-remove-indentation
- (org-element-property :value fixed-width)))))
-
-
-;;;; Footnote Definition
-;;
-;; Footnote Definitions are ignored.
-
-
-;;;; Footnote Reference
-;;
-;; Footnote reference export is handled by
-;; `org-e-latex-footnote-reference'.
-;;
-;; Internally, `org-e-latex--get-footnote-counter' is used to restore
-;; the value of the LaTeX "footnote" counter after a jump due to
-;; a reference to an already defined footnote. It is only needed in
-;; item tags since the optional argument to \footnotemark is not
-;; allowed there.
-
-(defun org-e-latex--get-footnote-counter (footnote-reference info)
- "Return \"footnote\" counter before FOOTNOTE-REFERENCE is encountered.
-INFO is a plist used as a communication channel."
- ;; Find original counter value by counting number of footnote
- ;; references appearing for the first time before the current
- ;; footnote reference.
- (let* ((label (org-element-property :label footnote-reference))
- seen-refs
- search-ref ; For byte-compiler.
- (search-ref
- (function
- (lambda (data)
- ;; Search footnote references through DATA, filling
- ;; SEEN-REFS along the way.
- (org-element-map
- data 'footnote-reference
- (lambda (fn)
- (let ((fn-lbl (org-element-property :label fn)))
- (cond
- ;; Anonymous footnote match: return number.
- ((eq fn footnote-reference) (length seen-refs))
- ;; Anonymous footnote: it's always a new one.
- ;; Also, be sure to return nil from the `cond' so
- ;; `first-match' doesn't get us out of the loop.
- ((not fn-lbl) (push 'inline seen-refs) nil)
- ;; Label not seen so far: add it so SEEN-REFS.
- ;;
- ;; Also search for subsequent references in
- ;; footnote definition so numbering follows reading
- ;; logic. Note that we don't have to care about
- ;; inline definitions, since `org-element-map'
- ;; already traverse them at the right time.
- ((not (member fn-lbl seen-refs))
- (push fn-lbl seen-refs)
- (funcall search-ref
- (org-export-get-footnote-definition fn info))))))
- ;; Don't enter footnote definitions since it will happen
- ;; when their first reference is found.
- info 'first-match 'footnote-definition)))))
- (funcall search-ref (plist-get info :parse-tree))))
-
-(defun org-e-latex-footnote-reference (footnote-reference contents info)
- "Transcode a FOOTNOTE-REFERENCE element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (concat
- ;; Insert separator between two footnotes in a row.
- (let ((prev (org-export-get-previous-element footnote-reference info)))
- (when (eq (org-element-type prev) 'footnote-reference)
- org-e-latex-footnote-separator))
- (cond
- ;; Use \footnotemark if reference is within an item's tag.
- ((eq (org-element-type (org-export-get-parent-element footnote-reference))
- 'item)
- (if (org-export-footnote-first-reference-p footnote-reference info)
- "\\footnotemark"
- ;; Since we can't specify footnote number as an optional
- ;; argument within an item tag, some extra work has to be done
- ;; when the footnote has already been referenced. In that
- ;; case, set footnote counter to the desired number, use the
- ;; footnotemark, then set counter back to its original value.
- (format
- "\\setcounter{footnote}{%s}\\footnotemark\\setcounter{footnote}{%s}"
- (1- (org-export-get-footnote-number footnote-reference info))
- (org-e-latex--get-footnote-counter footnote-reference info))))
- ;; Use \footnotemark if the footnote has already been defined.
- ((not (org-export-footnote-first-reference-p footnote-reference info))
- (format "\\footnotemark[%s]{}"
- (org-export-get-footnote-number footnote-reference info)))
- ;; Use \footnotemark if reference is within another footnote
- ;; reference or footnote definition.
- ((loop for parent in (org-export-get-genealogy footnote-reference)
- thereis (memq (org-element-type parent)
- '(footnote-reference footnote-definition)))
- "\\footnotemark")
- ;; Otherwise, define it with \footnote command.
- (t
- (let ((def (org-export-get-footnote-definition footnote-reference info)))
- (unless (eq (org-element-type def) 'org-data)
- (setq def (cons 'org-data (cons nil def))))
- (concat
- (format "\\footnote{%s}" (org-trim (org-export-data def info)))
- ;; Retrieve all footnote references within the footnote and
- ;; add their definition after it, since LaTeX doesn't support
- ;; them inside.
- (org-e-latex--delayed-footnotes-definitions def info)))))))
-
-
-;;;; Headline
-
-(defun org-e-latex-headline (headline contents info)
- "Transcode an HEADLINE element from Org to LaTeX.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- (let* ((class (plist-get info :latex-class))
- (level (org-export-get-relative-level headline info))
- (numberedp (org-export-numbered-headline-p headline info))
- (class-sectionning (assoc class org-e-latex-classes))
- ;; Section formatting will set two placeholders: one for the
- ;; title and the other for the contents.
- (section-fmt
- (let ((sec (if (and (symbolp (nth 2 class-sectionning))
- (fboundp (nth 2 class-sectionning)))
- (funcall (nth 2 class-sectionning) level numberedp)
- (nth (1+ level) class-sectionning))))
- (cond
- ;; No section available for that LEVEL.
- ((not sec) nil)
- ;; Section format directly returned by a function.
- ((stringp sec) sec)
- ;; (numbered-section . unnumbered-section)
- ((not (consp (cdr sec)))
- (concat (funcall (if numberedp #'car #'cdr) sec) "\n%s"))
- ;; (numbered-open numbered-close)
- ((= (length sec) 2)
- (when numberedp (concat (car sec) "\n%s" (nth 1 sec))))
- ;; (num-in num-out no-num-in no-num-out)
- ((= (length sec) 4)
- (if numberedp (concat (car sec) "\n%s" (nth 1 sec))
- (concat (nth 2 sec) "\n%s" (nth 3 sec)))))))
- (text (org-export-data (org-element-property :title headline) info))
- (todo
- (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword headline)))
- (and todo (org-export-data todo info)))))
- (todo-type (and todo (org-element-property :todo-type headline)))
- (tags (and (plist-get info :with-tags)
- (org-export-get-tags headline info)))
- (priority (and (plist-get info :with-priority)
- (org-element-property :priority headline)))
- ;; Create the headline text along with a no-tag version. The
- ;; latter is required to remove tags from table of contents.
- (full-text (if (functionp org-e-latex-format-headline-function)
- ;; User-defined formatting function.
- (funcall org-e-latex-format-headline-function
- todo todo-type priority text tags)
- ;; Default formatting.
- (concat
- (when todo
- (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
- (when priority (format "\\framebox{\\#%c} " priority))
- text
- (when tags
- (format "\\hfill{}\\textsc{:%s:}"
- (mapconcat 'identity tags ":"))))))
- (full-text-no-tag
- (if (functionp org-e-latex-format-headline-function)
- ;; User-defined formatting function.
- (funcall org-e-latex-format-headline-function
- todo todo-type priority text nil)
- ;; Default formatting.
- (concat
- (when todo (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
- (when priority (format "\\framebox{\\#%c} " priority))
- text)))
- ;; Associate some \label to the headline for internal links.
- (headline-label
- (format "\\label{sec-%s}\n"
- (mapconcat 'number-to-string
- (org-export-get-headline-number headline info)
- "-")))
- (pre-blanks
- (make-string (org-element-property :pre-blank headline) 10)))
- (cond
- ;; Case 1: This is a footnote section: ignore it.
- ((org-element-property :footnote-section-p headline) nil)
- ;; Case 2. This is a deep sub-tree: export it as a list item.
- ;; Also export as items headlines for which no section
- ;; format has been found.
- ((or (not section-fmt) (org-export-low-level-p headline info))
- ;; Build the real contents of the sub-tree.
- (let ((low-level-body
- (concat
- ;; If the headline is the first sibling, start a list.
- (when (org-export-first-sibling-p headline info)
- (format "\\begin{%s}\n" (if numberedp 'enumerate 'itemize)))
- ;; Itemize headline
- "\\item " full-text "\n" headline-label pre-blanks contents)))
- ;; If headline is not the last sibling simply return
- ;; LOW-LEVEL-BODY. Otherwise, also close the list, before any
- ;; blank line.
- (if (not (org-export-last-sibling-p headline info)) low-level-body
- (replace-regexp-in-string
- "[ \t\n]*\\'"
- (format "\n\\\\end{%s}" (if numberedp 'enumerate 'itemize))
- low-level-body))))
- ;; Case 3. Standard headline. Export it as a section.
- (t
- (cond
- ((not (and tags (eq (plist-get info :with-tags) 'not-in-toc)))
- ;; Regular section. Use specified format string.
- (format section-fmt full-text
- (concat headline-label pre-blanks contents)))
- ((string-match "\\`\\\\\\(.*?\\){" section-fmt)
- ;; If tags should be removed from table of contents, insert
- ;; title without tags as an alternative heading in sectioning
- ;; command.
- (format (replace-match (concat (match-string 1 section-fmt) "[%s]")
- nil nil section-fmt 1)
- ;; Replace square brackets with parenthesis since
- ;; square brackets are not supported in optional
- ;; arguments.
- (replace-regexp-in-string
- "\\[" "("
- (replace-regexp-in-string
- "\\]" ")"
- full-text-no-tag))
- full-text
- (concat headline-label pre-blanks contents)))
- (t
- ;; Impossible to add an alternative heading. Fallback to
- ;; regular sectioning format string.
- (format section-fmt full-text
- (concat headline-label pre-blanks contents))))))))
-
-
-;;;; Horizontal Rule
-
-(defun org-e-latex-horizontal-rule (horizontal-rule contents info)
- "Transcode an HORIZONTAL-RULE object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((attr (org-export-read-attribute :attr_latex horizontal-rule))
- (prev (org-export-get-previous-element horizontal-rule info)))
- (concat
- ;; Make sure the rule doesn't start at the end of the current
- ;; line by separating it with a blank line from previous element.
- (when (and prev
- (let ((prev-blank (org-element-property :post-blank prev)))
- (or (not prev-blank) (zerop prev-blank))))
- "\n")
- (org-e-latex--wrap-label
- horizontal-rule
- (format "\\rule{%s}{%s}"
- (or (plist-get attr :width) "\\linewidth")
- (or (plist-get attr :thickness) "0.5pt"))))))
-
-
-;;;; Inline Babel Call
-;;
-;; Inline Babel Calls are ignored.
-
-
-;;;; Inline Src Block
-
-(defun org-e-latex-inline-src-block (inline-src-block contents info)
- "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((code (org-element-property :value inline-src-block))
- (separator (org-e-latex--find-verb-separator code)))
- (cond
- ;; Do not use a special package: transcode it verbatim.
- ((not org-e-latex-listings)
- (concat "\\verb" separator code separator))
- ;; Use minted package.
- ((eq org-e-latex-listings 'minted)
- (let* ((org-lang (org-element-property :language inline-src-block))
- (mint-lang (or (cadr (assq (intern org-lang)
- org-e-latex-minted-langs))
- org-lang))
- (options (org-e-latex--make-option-string
- org-e-latex-minted-options)))
- (concat (format "\\mint%s{%s}"
- (if (string= options "") "" (format "[%s]" options))
- mint-lang)
- separator code separator)))
- ;; Use listings package.
- (t
- ;; Maybe translate language's name.
- (let* ((org-lang (org-element-property :language inline-src-block))
- (lst-lang (or (cadr (assq (intern org-lang)
- org-e-latex-listings-langs))
- org-lang))
- (options (org-e-latex--make-option-string
- (append org-e-latex-listings-options
- `(("language" ,lst-lang))))))
- (concat (format "\\lstinline[%s]" options)
- separator code separator))))))
-
-
-;;;; Inlinetask
-
-(defun org-e-latex-inlinetask (inlinetask contents info)
- "Transcode an INLINETASK element from Org to LaTeX.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((title (org-export-data (org-element-property :title inlinetask) info))
- (todo (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword inlinetask)))
- (and todo (org-export-data todo info)))))
- (todo-type (org-element-property :todo-type inlinetask))
- (tags (and (plist-get info :with-tags)
- (org-export-get-tags inlinetask info)))
- (priority (and (plist-get info :with-priority)
- (org-element-property :priority inlinetask))))
- ;; If `org-e-latex-format-inlinetask-function' is provided, call it
- ;; with appropriate arguments.
- (if (functionp org-e-latex-format-inlinetask-function)
- (funcall org-e-latex-format-inlinetask-function
- todo todo-type priority title tags contents)
- ;; Otherwise, use a default template.
- (org-e-latex--wrap-label
- inlinetask
- (let ((full-title
- (concat
- (when todo (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
- (when priority (format "\\framebox{\\#%c} " priority))
- title
- (when tags (format "\\hfill{}\\textsc{:%s:}"
- (mapconcat 'identity tags ":"))))))
- (format (concat "\\begin{center}\n"
- "\\fbox{\n"
- "\\begin{minipage}[c]{.6\\textwidth}\n"
- "%s\n\n"
- "\\rule[.8em]{\\textwidth}{2pt}\n\n"
- "%s"
- "\\end{minipage}\n"
- "}\n"
- "\\end{center}")
- full-title contents))))))
-
-
-;;;; Italic
-
-(defun org-e-latex-italic (italic contents info)
- "Transcode ITALIC from Org to LaTeX.
-CONTENTS is the text with italic markup. INFO is a plist holding
-contextual information."
- (org-e-latex--text-markup contents 'italic))
-
-
-;;;; Item
-
-(defun org-e-latex-item (item contents info)
- "Transcode an ITEM element from Org to LaTeX.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((counter
- (let ((count (org-element-property :counter item))
- (level
- (loop for parent in (org-export-get-genealogy item)
- count (eq (org-element-type parent) 'plain-list)
- until (eq (org-element-type parent) 'headline))))
- (and count
- (< level 5)
- (format "\\setcounter{enum%s}{%s}\n"
- (nth (1- level) '("i" "ii" "iii" "iv"))
- (1- count)))))
- (checkbox (case (org-element-property :checkbox item)
- (on "$\\boxtimes$ ")
- (off "$\\Box$ ")
- (trans "$\\boxminus$ ")))
- (tag (let ((tag (org-element-property :tag item)))
- ;; Check-boxes must belong to the tag.
- (and tag (format "[%s] "
- (concat checkbox
- (org-export-data tag info)))))))
- (concat counter "\\item" (or tag (concat " " checkbox))
- (and contents (org-trim contents))
- ;; If there are footnotes references in tag, be sure to
- ;; add their definition at the end of the item. This
- ;; workaround is necessary since "\footnote{}" command is
- ;; not supported in tags.
- (and tag
- (org-e-latex--delayed-footnotes-definitions
- (org-element-property :tag item) info)))))
-
-
-;;;; Keyword
-
-(defun org-e-latex-keyword (keyword contents info)
- "Transcode a KEYWORD element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((key (org-element-property :key keyword))
- (value (org-element-property :value keyword)))
- (cond
- ((string= key "LATEX") value)
- ((string= key "INDEX") (format "\\index{%s}" value))
- ;; Invisible targets.
- ((string= key "TARGET") nil)
- ((string= key "TOC")
- (let ((value (downcase value)))
- (cond
- ((string-match "\\<headlines\\>" value)
- (let ((depth (or (and (string-match "[0-9]+" value)
- (string-to-number (match-string 0 value)))
- (plist-get info :with-toc))))
- (concat
- (when (wholenump depth)
- (format "\\setcounter{tocdepth}{%s}\n" depth))
- "\\tableofcontents")))
- ((string= "tables" value) "\\listoftables")
- ((string= "figures" value) "\\listoffigures")
- ((string= "listings" value)
- (cond
- ((eq org-e-latex-listings 'minted) "\\listoflistings")
- (org-e-latex-listings "\\lstlistoflistings")
- ;; At the moment, src blocks with a caption are wrapped
- ;; into a figure environment.
- (t "\\listoffigures")))))))))
-
-
-;;;; Latex Environment
-
-(defun org-e-latex-latex-environment (latex-environment contents info)
- "Transcode a LATEX-ENVIRONMENT element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((label (org-element-property :name latex-environment))
- (value (org-remove-indentation
- (org-element-property :value latex-environment))))
- (if (not (org-string-nw-p label)) value
- ;; Environment is labelled: label must be within the environment
- ;; (otherwise, a reference pointing to that element will count
- ;; the section instead).
- (with-temp-buffer
- (insert value)
- (goto-char (point-min))
- (forward-line)
- (insert (format "\\label{%s}\n" label))
- (buffer-string)))))
-
-
-;;;; Latex Fragment
-
-(defun org-e-latex-latex-fragment (latex-fragment contents info)
- "Transcode a LATEX-FRAGMENT object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-element-property :value latex-fragment))
-
-
-;;;; Line Break
-
-(defun org-e-latex-line-break (line-break contents info)
- "Transcode a LINE-BREAK object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- "\\\\")
-
-
-;;;; Link
-
-(defun org-e-latex-link--inline-image (link info)
- "Return LaTeX code for an inline image.
-LINK is the link pointing to the inline image. INFO is a plist
-used as a communication channel."
- (let* ((parent (org-export-get-parent-element link))
- (path (let ((raw-path (org-element-property :path link)))
- (if (not (file-name-absolute-p raw-path)) raw-path
- (expand-file-name raw-path))))
- (caption (org-e-latex--caption/label-string
- (org-element-property :caption parent)
- (org-element-property :name parent)
- info))
- ;; Retrieve latex attributes from the element around.
- (attr (let ((raw-attr
- (mapconcat #'identity
- (org-element-property :attr_latex parent)
- " ")))
- (unless (string= raw-attr "") raw-attr)))
- (disposition
- (cond
- ((and attr (string-match "\\<wrap\\>" attr)) 'wrap)
- ((and attr (string-match "\\<multicolumn\\>" attr)) 'multicolumn)
- ((or (and attr (string-match "\\<float\\>" attr))
- (not (string= caption "")))
- 'float)))
- (placement
- (cond
- ((and attr (string-match "\\<placement=\\(\\S-+\\)" attr))
- (org-match-string-no-properties 1 attr))
- ((eq disposition 'wrap) "{l}{0.5\\textwidth}")
- ((eq disposition 'float)
- (concat "[" org-e-latex-default-figure-position "]"))
- (t ""))))
- ;; Now clear ATTR from any special keyword and set a default
- ;; value if nothing is left.
- (setq attr
- (if (not attr) ""
- (org-trim
- (replace-regexp-in-string
- "\\(wrap\\|multicolumn\\|float\\|placement=\\S-+\\)" "" attr))))
- (setq attr (cond ((not (string= attr "")) attr)
- ((eq disposition 'float) "width=0.7\\textwidth")
- ((eq disposition 'wrap) "width=0.48\\textwidth")
- (t (or org-e-latex-image-default-option ""))))
- ;; Return proper string, depending on DISPOSITION.
- (case disposition
- (wrap (format "\\begin{wrapfigure}%s
-\\centering
-\\includegraphics[%s]{%s}
-%s\\end{wrapfigure}" placement attr path caption))
- (multicolumn (format "\\begin{figure*}%s
-\\centering
-\\includegraphics[%s]{%s}
-%s\\end{figure*}" placement attr path caption))
- (float (format "\\begin{figure}%s
-\\centering
-\\includegraphics[%s]{%s}
-%s\\end{figure}" placement attr path caption))
- (t (format "\\includegraphics[%s]{%s}" attr path)))))
-
-(defun org-e-latex-link (link desc info)
- "Transcode a LINK object from Org to LaTeX.
-
-DESC is the description part of the link, or the empty string.
-INFO is a plist holding contextual information. See
-`org-export-data'."
- (let* ((type (org-element-property :type link))
- (raw-path (org-element-property :path link))
- ;; Ensure DESC really exists, or set it to nil.
- (desc (and (not (string= desc "")) desc))
- (imagep (org-export-inline-image-p
- link org-e-latex-inline-image-rules))
- (path (cond
- ((member type '("http" "https" "ftp" "mailto"))
- (concat type ":" raw-path))
- ((string= type "file")
- (when (string-match "\\(.+\\)::.+" raw-path)
- (setq raw-path (match-string 1 raw-path)))
- (if (file-name-absolute-p raw-path)
- (concat "file://" (expand-file-name raw-path))
- (concat "file://" raw-path)))
- (t raw-path)))
- protocol)
- (cond
- ;; Image file.
- (imagep (org-e-latex-link--inline-image link info))
- ;; Radio link: Transcode target's contents and use them as link's
- ;; description.
- ((string= type "radio")
- (let ((destination (org-export-resolve-radio-link link info)))
- (when destination
- (format "\\hyperref[%s]{%s}"
- (org-export-solidify-link-text path)
- (org-export-data (org-element-contents destination) info)))))
- ;; Links pointing to an headline: Find destination and build
- ;; appropriate referencing command.
- ((member type '("custom-id" "fuzzy" "id"))
- (let ((destination (if (string= type "fuzzy")
- (org-export-resolve-fuzzy-link link info)
- (org-export-resolve-id-link link info))))
- (case (org-element-type destination)
- ;; Id link points to an external file.
- (plain-text
- (if desc (format "\\href{file://%s}{%s}" destination desc)
- (format "\\url{file://%s}" destination)))
- ;; Fuzzy link points nowhere.
- ('nil
- (format org-e-latex-link-with-unknown-path-format
- (or desc
- (org-export-data
- (org-element-property :raw-link link) info))))
- ;; Fuzzy link points to an invisible target.
- (keyword nil)
- ;; LINK points to an headline. If headlines are numbered
- ;; and the link has no description, display headline's
- ;; number. Otherwise, display description or headline's
- ;; title.
- (headline
- (let ((label
- (format "sec-%s"
- (mapconcat
- 'number-to-string
- (org-export-get-headline-number destination info)
- "-"))))
- (if (and (plist-get info :section-numbers) (not desc))
- (format "\\ref{%s}" label)
- (format "\\hyperref[%s]{%s}" label
- (or desc
- (org-export-data
- (org-element-property :title destination) info))))))
- ;; Fuzzy link points to a target. Do as above.
- (otherwise
- (let ((path (org-export-solidify-link-text path)))
- (if (not desc) (format "\\ref{%s}" path)
- (format "\\hyperref[%s]{%s}" path desc)))))))
- ;; Coderef: replace link with the reference name or the
- ;; equivalent line number.
- ((string= type "coderef")
- (format (org-export-get-coderef-format path desc)
- (org-export-resolve-coderef path info)))
- ;; Link type is handled by a special function.
- ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
- (funcall protocol (org-link-unescape path) desc 'latex))
- ;; External link with a description part.
- ((and path desc) (format "\\href{%s}{%s}" path desc))
- ;; External link without a description part.
- (path (format "\\url{%s}" path))
- ;; No path, only description. Try to do something useful.
- (t (format org-e-latex-link-with-unknown-path-format desc)))))
-
-
-;;;; Macro
-
-(defun org-e-latex-macro (macro contents info)
- "Transcode a MACRO element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- ;; Use available tools.
- (org-export-expand-macro macro info))
-
-
-;;;; Paragraph
-
-(defun org-e-latex-paragraph (paragraph contents info)
- "Transcode a PARAGRAPH element from Org to LaTeX.
-CONTENTS is the contents of the paragraph, as a string. INFO is
-the plist used as a communication channel."
- contents)
-
-
-;;;; Plain List
-
-(defun org-e-latex-plain-list (plain-list contents info)
- "Transcode a PLAIN-LIST element from Org to LaTeX.
-CONTENTS is the contents of the list. INFO is a plist holding
-contextual information."
- (let* ((type (org-element-property :type plain-list))
- (paralist-types '("inparaenum" "asparaenum" "inparaitem" "asparaitem"
- "inparadesc" "asparadesc"))
- (paralist-regexp (concat
- "\\("
- (mapconcat 'identity paralist-types "\\|")
- "\\)"))
- (attr (mapconcat #'identity
- (org-element-property :attr_latex plain-list)
- " "))
- (latex-type (cond
- ((and attr
- (string-match
- (format "\\<%s\\>" paralist-regexp) attr))
- (match-string 1 attr))
- ((eq type 'ordered) "enumerate")
- ((eq type 'unordered) "itemize")
- ((eq type 'descriptive) "description"))))
- (org-e-latex--wrap-label
- plain-list
- (format "\\begin{%s}%s\n%s\\end{%s}"
- latex-type
- ;; Once special environment, if any, has been removed, the
- ;; rest of the attributes will be optional arguments.
- ;; They will be put inside square brackets if necessary.
- (let ((opt (replace-regexp-in-string
- (format " *%s *" paralist-regexp) "" attr)))
- (cond ((string= opt "") "")
- ((string-match "\\`\\[[^][]+\\]\\'" opt) opt)
- (t (format "[%s]" opt))))
- contents
- latex-type))))
-
-
-;;;; Plain Text
-
-(defun org-e-latex-plain-text (text info)
- "Transcode a TEXT string from Org to LaTeX.
-TEXT is the string to transcode. INFO is a plist holding
-contextual information."
- ;; Protect %, #, &, $, ~, ^, _, { and }.
- (while (string-match "\\([^\\]\\|^\\)\\([%$#&{}~^_]\\)" text)
- (setq text
- (replace-match (format "\\%s" (match-string 2 text)) nil t text 2)))
- ;; Protect \
- (setq text (replace-regexp-in-string
- "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
- "$\\backslash$" text nil t 1))
- ;; LaTeX into \LaTeX{} and TeX into \TeX{}.
- (let ((case-fold-search nil)
- (start 0))
- (while (string-match "\\<\\(\\(?:La\\)?TeX\\)\\>" text start)
- (setq text (replace-match
- (format "\\%s{}" (match-string 1 text)) nil t text)
- start (match-end 0))))
- ;; Handle quotation marks
- (setq text (org-e-latex--quotation-marks text info))
- ;; Convert special strings.
- (when (plist-get info :with-special-strings)
- (while (string-match (regexp-quote "...") text)
- (setq text (replace-match "\\ldots{}" nil t text))))
- ;; Handle break preservation if required.
- (when (plist-get info :preserve-breaks)
- (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
- text)))
- ;; Return value.
- text)
-
-
-;;;; Planning
-
-(defun org-e-latex-planning (planning contents info)
- "Transcode a PLANNING element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (concat
- "\\noindent"
- (mapconcat
- 'identity
- (delq nil
- (list
- (let ((closed (org-element-property :closed planning)))
- (when closed
- (concat
- (format "\\textbf{%s} " org-closed-string)
- (format org-e-latex-inactive-timestamp-format
- (org-translate-time closed)))))
- (let ((deadline (org-element-property :deadline planning)))
- (when deadline
- (concat
- (format "\\textbf{%s} " org-deadline-string)
- (format org-e-latex-active-timestamp-format
- (org-translate-time deadline)))))
- (let ((scheduled (org-element-property :scheduled planning)))
- (when scheduled
- (concat
- (format "\\textbf{%s} " org-scheduled-string)
- (format org-e-latex-active-timestamp-format
- (org-translate-time scheduled)))))))
- " ")
- "\\\\"))
-
-
-;;;; Property Drawer
-
-(defun org-e-latex-property-drawer (property-drawer contents info)
- "Transcode a PROPERTY-DRAWER element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- ;; The property drawer isn't exported but we want separating blank
- ;; lines nonetheless.
- "")
-
-
-;;;; Quote Block
-
-(defun org-e-latex-quote-block (quote-block contents info)
- "Transcode a QUOTE-BLOCK element from Org to LaTeX.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (org-e-latex--wrap-label
- quote-block
- (format "\\begin{quote}\n%s\\end{quote}" contents)))
-
-
-;;;; Quote Section
-
-(defun org-e-latex-quote-section (quote-section contents info)
- "Transcode a QUOTE-SECTION element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((value (org-remove-indentation
- (org-element-property :value quote-section))))
- (when value (format "\\begin{verbatim}\n%s\\end{verbatim}" value))))
-
-
-;;;; Radio Target
-
-(defun org-e-latex-radio-target (radio-target text info)
- "Transcode a RADIO-TARGET object from Org to LaTeX.
-TEXT is the text of the target. INFO is a plist holding
-contextual information."
- (format "\\label{%s}%s"
- (org-export-solidify-link-text
- (org-element-property :value radio-target))
- text))
-
-
-;;;; Section
-
-(defun org-e-latex-section (section contents info)
- "Transcode a SECTION element from Org to LaTeX.
-CONTENTS holds the contents of the section. INFO is a plist
-holding contextual information."
- contents)
-
-
-;;;; Special Block
-
-(defun org-e-latex-special-block (special-block contents info)
- "Transcode a SPECIAL-BLOCK element from Org to LaTeX.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((type (downcase (org-element-property :type special-block))))
- (org-e-latex--wrap-label
- special-block
- (format "\\begin{%s}\n%s\\end{%s}" type contents type))))
-
-
-;;;; Src Block
-
-(defun org-e-latex-src-block (src-block contents info)
- "Transcode a SRC-BLOCK element from Org to LaTeX.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((lang (org-element-property :language src-block))
- (caption (org-element-property :caption src-block))
- (label (org-element-property :name src-block))
- (custom-env (and lang
- (cadr (assq (intern lang)
- org-e-latex-custom-lang-environments))))
- (num-start (case (org-element-property :number-lines src-block)
- (continued (org-export-get-loc src-block info))
- (new 0)))
- (retain-labels (org-element-property :retain-labels src-block)))
- (cond
- ;; Case 1. No source fontification.
- ((not org-e-latex-listings)
- (let ((caption-str (org-e-latex--caption/label-string caption label info))
- (float-env (when caption "\\begin{figure}[H]\n%s\n\\end{figure}")))
- (format
- (or float-env "%s")
- (concat caption-str
- (format "\\begin{verbatim}\n%s\\end{verbatim}"
- (org-export-format-code-default src-block info))))))
- ;; Case 2. Custom environment.
- (custom-env (format "\\begin{%s}\n%s\\end{%s}\n"
- custom-env
- (org-export-format-code-default src-block info)
- custom-env))
- ;; Case 3. Use minted package.
- ((eq org-e-latex-listings 'minted)
- (let ((float-env (when (or label caption)
- (format "\\begin{listing}[H]\n%%s\n%s\\end{listing}"
- (org-e-latex--caption/label-string
- caption label info))))
- (body
- (format
- "\\begin{minted}[%s]{%s}\n%s\\end{minted}"
- ;; Options.
- (org-e-latex--make-option-string
- (if (not num-start) org-e-latex-minted-options
- (append `(("linenos")
- ("firstnumber" ,(number-to-string (1+ num-start))))
- org-e-latex-minted-options)))
- ;; Language.
- (or (cadr (assq (intern lang) org-e-latex-minted-langs)) lang)
- ;; Source code.
- (let* ((code-info (org-export-unravel-code src-block))
- (max-width
- (apply 'max
- (mapcar 'length
- (org-split-string (car code-info) "\n")))))
- (org-export-format-code
- (car code-info)
- (lambda (loc num ref)
- (concat
- loc
- (when ref
- ;; Ensure references are flushed to the right,
- ;; separated with 6 spaces from the widest line
- ;; of code.
- (concat (make-string (+ (- max-width (length loc)) 6) ? )
- (format "(%s)" ref)))))
- nil (and retain-labels (cdr code-info)))))))
- ;; Return value.
- (if float-env (format float-env body) body)))
- ;; Case 4. Use listings package.
- (t
- (let ((lst-lang
- (or (cadr (assq (intern lang) org-e-latex-listings-langs)) lang))
- (caption-str
- (when caption
- (let ((main (org-export-data (car caption) info)))
- (if (not (cdr caption)) (format "{%s}" main)
- (format "{[%s]%s}"
- (org-export-data (cdr caption) info)
- main))))))
- (concat
- ;; Options.
- (format "\\lstset{%s}\n"
- (org-e-latex--make-option-string
- (append org-e-latex-listings-options
- `(("language" ,lst-lang))
- (when label `(("label" ,label)))
- (when caption-str `(("caption" ,caption-str)))
- (cond ((not num-start) '(("numbers" "none")))
- ((zerop num-start) '(("numbers" "left")))
- (t `(("numbers" "left")
- ("firstnumber"
- ,(number-to-string (1+ num-start)))))))))
- ;; Source code.
- (format
- "\\begin{lstlisting}\n%s\\end{lstlisting}"
- (let* ((code-info (org-export-unravel-code src-block))
- (max-width
- (apply 'max
- (mapcar 'length
- (org-split-string (car code-info) "\n")))))
- (org-export-format-code
- (car code-info)
- (lambda (loc num ref)
- (concat
- loc
- (when ref
- ;; Ensure references are flushed to the right,
- ;; separated with 6 spaces from the widest line of
- ;; code
- (concat (make-string (+ (- max-width (length loc)) 6) ? )
- (format "(%s)" ref)))))
- nil (and retain-labels (cdr code-info)))))))))))
-
-
-;;;; Statistics Cookie
-
-(defun org-e-latex-statistics-cookie (statistics-cookie contents info)
- "Transcode a STATISTICS-COOKIE object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (replace-regexp-in-string
- "%" "\\%" (org-element-property :value statistics-cookie) nil t))
-
-
-;;;; Strike-Through
-
-(defun org-e-latex-strike-through (strike-through contents info)
- "Transcode STRIKE-THROUGH from Org to LaTeX.
-CONTENTS is the text with strike-through markup. INFO is a plist
-holding contextual information."
- (org-e-latex--text-markup contents 'strike-through))
-
-
-;;;; Subscript
-
-(defun org-e-latex-subscript (subscript contents info)
- "Transcode a SUBSCRIPT object from Org to LaTeX.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (if (= (length contents) 1) (format "$_%s$" contents)
- ;; Handle multiple objects in SUBSCRIPT by creating a subscript
- ;; command for each of them.
- (let ((prev-blanks 0))
- (mapconcat
- (lambda (obj)
- (case (org-element-type obj)
- ((entity latex-fragment)
- (setq prev-blanks (org-element-property :post-blank obj))
- (let ((data (org-trim (org-export-data obj info))))
- (string-match
- "\\`\\(?:\\\\[([]\\|\\$+\\)?\\(.*?\\)\\(?:\\\\[])]\\|\\$+\\)?\\'"
- data)
- (format "$_{%s}$" (match-string 1 data))))
- (plain-text
- (format "$_\\mathrm{%s}$"
- (concat (make-string prev-blanks ? )
- ;; mathrm command doesn't handle spaces,
- ;; so we have to enforce them.
- (replace-regexp-in-string
- " " "\\\\ " (org-export-data obj info)))))
- (otherwise
- (setq prev-blanks (org-element-property :post-blank obj))
- (format "$_{%s}$" (org-export-data obj info)))))
- (org-element-contents subscript) ""))))
-
-
-;;;; Superscript
-
-(defun org-e-latex-superscript (superscript contents info)
- "Transcode a SUPERSCRIPT object from Org to LaTeX.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (if (= (length contents) 1) (format "$^%s$" contents)
- ;; Handle multiple objects in SUPERSCRIPT by creating
- ;; a superscript command for each of them.
- (let ((prev-blanks 0))
- (mapconcat
- (lambda (obj)
- (case (org-element-type obj)
- ((entity latex-fragment)
- (setq prev-blanks (org-element-property :post-blank obj))
- (let ((data (org-trim (org-export-data obj info))))
- (string-match
- "\\`\\(?:\\\\[([]\\|\\$+\\)?\\(.*?\\)\\(?:\\\\[])]\\|\\$+\\)?\\'"
- data)
- (format "$^{%s}$" (match-string 1 data))))
- (plain-text
- (format "$^\\mathrm{%s}$"
- (concat (make-string prev-blanks ? )
- ;; mathrm command doesn't handle spaces,
- ;; so we have to enforce them.
- (replace-regexp-in-string
- " " "\\\\ " (org-export-data obj info)))))
- (otherwise
- (setq prev-blanks (org-element-property :post-blank obj))
- (format "$^{%s}$" (org-export-data obj info)))))
- (org-element-contents superscript) ""))))
-
-
-;;;; Table
-;;
-;; `org-e-latex-table' is the entry point for table transcoding. It
-;; takes care of tables with a "verbatim" attribute. Otherwise, it
-;; delegates the job to either `org-e-latex-table--table.el-table' or
-;; `org-e-latex-table--org-table' functions, depending of the type of
-;; the table.
-;;
-;; `org-e-latex-table--align-string' is a subroutine used to build
-;; alignment string for Org tables.
-
-(defun org-e-latex-table (table contents info)
- "Transcode a TABLE element from Org to LaTeX.
-CONTENTS is the contents of the table. INFO is a plist holding
-contextual information."
- (cond
- ;; Case 1: verbatim table.
- ((or org-e-latex-tables-verbatim
- (let ((attr (mapconcat 'identity
- (org-element-property :attr_latex table)
- " ")))
- (and attr (string-match "\\<verbatim\\>" attr))))
- (format "\\begin{verbatim}\n%s\n\\end{verbatim}"
- ;; Re-create table, without affiliated keywords.
- (org-trim
- (org-element-interpret-data
- `(table nil ,@(org-element-contents table))))))
- ;; Case 2: table.el table. Convert it using appropriate tools.
- ((eq (org-element-property :type table) 'table.el)
- (org-e-latex-table--table.el-table table contents info))
- ;; Case 3: Standard table.
- (t (org-e-latex-table--org-table table contents info))))
-
-(defun org-e-latex-table--align-string (table info)
- "Return an appropriate LaTeX alignment string.
-TABLE is the considered table. INFO is a plist used as
-a communication channel."
- (let ((attr (mapconcat 'identity
- (org-element-property :attr_latex table)
- " ")))
- (if (string-match "\\<align=\\(\\S-+\\)" attr) (match-string 1 attr)
- (let (alignment)
- ;; Extract column groups and alignment from first (non-rule)
- ;; row.
- (org-element-map
- (org-element-map
- table 'table-row
- (lambda (row)
- (and (eq (org-element-property :type row) 'standard) row))
- info 'first-match)
- 'table-cell
- (lambda (cell)
- (let ((borders (org-export-table-cell-borders cell info)))
- ;; Check left border for the first cell only.
- (when (and (memq 'left borders) (not alignment))
- (push "|" alignment))
- (push (case (org-export-table-cell-alignment cell info)
- (left "l")
- (right "r")
- (center "c"))
- alignment)
- (when (memq 'right borders) (push "|" alignment))))
- info)
- (apply 'concat (reverse alignment))))))
-
-(defun org-e-latex-table--org-table (table contents info)
- "Return appropriate LaTeX code for an Org table.
-
-TABLE is the table type element to transcode. CONTENTS is its
-contents, as a string. INFO is a plist used as a communication
-channel.
-
-This function assumes TABLE has `org' as its `:type' attribute."
- (let* ((label (org-element-property :name table))
- (caption (org-e-latex--caption/label-string
- (org-element-property :caption table) label info))
- (attr (mapconcat 'identity
- (org-element-property :attr_latex table)
- " "))
- ;; Determine alignment string.
- (alignment (org-e-latex-table--align-string table info))
- ;; Determine environment for the table: longtable, tabular...
- (table-env (cond
- ((not attr) org-e-latex-default-table-environment)
- ((string-match "\\<longtable\\>" attr) "longtable")
- ((string-match "\\<tabular.?\\>" attr)
- (org-match-string-no-properties 0 attr))
- (t org-e-latex-default-table-environment)))
- ;; If table is a float, determine environment: table, table*
- ;; or sidewaystable.
- (float-env (cond
- ((string= "longtable" table-env) nil)
- ((and attr (string-match "\\<sidewaystable\\>" attr))
- "sidewaystable")
- ((and attr
- (or (string-match (regexp-quote "table*") attr)
- (string-match "\\<multicolumn\\>" attr)))
- "table*")
- ((or (not (string= caption "")) label) "table")))
- ;; Extract others display options.
- (width (and attr (string-match "\\<width=\\(\\S-+\\)" attr)
- (org-match-string-no-properties 1 attr)))
- (placement
- (if (and attr (string-match "\\<placement=\\(\\S-+\\)" attr))
- (org-match-string-no-properties 1 attr)
- (format "[%s]" org-e-latex-default-figure-position))))
- ;; Prepare the final format string for the table.
- (cond
- ;; Longtable.
- ((string= "longtable" table-env)
- (format
- "\\begin{longtable}{%s}\n%s%s%s\\end{longtable}"
- alignment
- (if (or (not org-e-latex-table-caption-above) (string= "" caption)) ""
- (concat (org-trim caption) "\\\\\n"))
- contents
- (if (or org-e-latex-table-caption-above (string= "" caption)) ""
- (concat (org-trim caption) "\\\\\n"))))
- ;; Others.
- (t (concat (when float-env
- (concat
- (format "\\begin{%s}%s\n" float-env placement)
- (if org-e-latex-table-caption-above caption "")))
- (when org-e-latex-tables-centered "\\begin{center}\n")
- (format "\\begin{%s}%s{%s}\n%s\\end{%s}"
- table-env
- (if width (format "{%s}" width) "")
- alignment
- contents
- table-env)
- (when org-e-latex-tables-centered "\n\\end{center}")
- (when float-env
- (concat (if org-e-latex-table-caption-above "" caption)
- (format "\n\\end{%s}" float-env))))))))
-
-(defun org-e-latex-table--table.el-table (table contents info)
- "Return appropriate LaTeX code for a table.el table.
-
-TABLE is the table type element to transcode. CONTENTS is its
-contents, as a string. INFO is a plist used as a communication
-channel.
-
-This function assumes TABLE has `table.el' as its `:type'
-attribute."
- (require 'table)
- ;; Ensure "*org-export-table*" buffer is empty.
- (with-current-buffer (get-buffer-create "*org-export-table*")
- (erase-buffer))
- (let ((output (with-temp-buffer
- (insert (org-element-property :value table))
- (goto-char 1)
- (re-search-forward "^[ \t]*|[^|]" nil t)
- (table-generate-source 'latex "*org-export-table*")
- (with-current-buffer "*org-export-table*"
- (org-trim (buffer-string))))))
- (kill-buffer (get-buffer "*org-export-table*"))
- ;; Remove left out comments.
- (while (string-match "^%.*\n" output)
- (setq output (replace-match "" t t output)))
- ;; When the "rmlines" attribute is provided, remove all hlines but
- ;; the the one separating heading from the table body.
- (let ((attr (mapconcat 'identity
- (org-element-property :attr_latex table)
- " ")))
- (when (and attr (string-match "\\<rmlines\\>" attr))
- (let ((n 0) (pos 0))
- (while (and (< (length output) pos)
- (setq pos (string-match "^\\\\hline\n?" output pos)))
- (incf n)
- (unless (= n 2)
- (setq output (replace-match "" nil nil output)))))))
- (if (not org-e-latex-tables-centered) output
- (format "\\begin{center}\n%s\n\\end{center}" output))))
-
-
-;;;; Table Cell
-
-(defun org-e-latex-table-cell (table-cell contents info)
- "Transcode a TABLE-CELL element from Org to LaTeX.
-CONTENTS is the cell contents. INFO is a plist used as
-a communication channel."
- (concat (if (and contents
- org-e-latex-table-scientific-notation
- (string-match orgtbl-exp-regexp contents))
- ;; Use appropriate format string for scientific
- ;; notation.
- (format org-e-latex-table-scientific-notation
- (match-string 1 contents)
- (match-string 2 contents))
- contents)
- (when (org-export-get-next-element table-cell info) " & ")))
-
-
-;;;; Table Row
-
-(defun org-e-latex-table-row (table-row contents info)
- "Transcode a TABLE-ROW element from Org to LaTeX.
-CONTENTS is the contents of the row. INFO is a plist used as
-a communication channel."
- ;; Rules are ignored since table separators are deduced from
- ;; borders of the current row.
- (when (eq (org-element-property :type table-row) 'standard)
- (let* ((attr (mapconcat 'identity
- (org-element-property
- :attr_latex (org-export-get-parent table-row))
- " "))
- (longtablep (and attr (string-match "\\<longtable\\>" attr)))
- (booktabsp
- (or (and attr (string-match "\\<booktabs=\\(yes\\|t\\)\\>" attr))
- org-e-latex-tables-booktabs))
- ;; TABLE-ROW's borders are extracted from its first cell.
- (borders
- (org-export-table-cell-borders
- (car (org-element-contents table-row)) info)))
- (concat
- ;; When BOOKTABS are activated enforce top-rule even when no
- ;; hline was specifically marked.
- (cond ((and booktabsp (memq 'top borders)) "\\toprule\n")
- ((and (memq 'top borders) (memq 'above borders)) "\\hline\n"))
- contents "\\\\\n"
- (cond
- ;; Special case for long tables. Define header and footers.
- ((and longtablep (org-export-table-row-ends-header-p table-row info))
- (format "%s
-\\endhead
-%s\\multicolumn{%d}{r}{Continued on next page} \\\\
-\\endfoot
-\\endlastfoot"
- (if booktabsp "\\midrule" "\\hline")
- (if booktabsp "\\midrule" "\\hline")
- ;; Number of columns.
- (cdr (org-export-table-dimensions
- (org-export-get-parent-table table-row) info))))
- ;; When BOOKTABS are activated enforce bottom rule even when
- ;; no hline was specifically marked.
- ((and booktabsp (memq 'bottom borders)) "\\bottomrule")
- ((and (memq 'bottom borders) (memq 'below borders)) "\\hline")
- ((memq 'below borders) (if booktabsp "\\midrule" "\\hline")))))))
-
-
-;;;; Target
-
-(defun org-e-latex-target (target contents info)
- "Transcode a TARGET object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format "\\label{%s}"
- (org-export-solidify-link-text (org-element-property :value target))))
-
-
-;;;; Timestamp
-
-(defun org-e-latex-timestamp (timestamp contents info)
- "Transcode a TIMESTAMP object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (let ((value (org-translate-time (org-element-property :value timestamp)))
- (range-end (org-element-property :range-end timestamp)))
- (case (org-element-property :type timestamp)
- (active (format org-e-latex-active-timestamp-format value))
- (active-range
- (concat (format org-e-latex-active-timestamp-format value)
- "--"
- (format org-e-latex-active-timestamp-format
- (org-translate-time range-end))))
- (inactive (format org-e-latex-inactive-timestamp-format value))
- (inactive-range
- (concat (format org-e-latex-inactive-timestamp-format value)
- "--"
- (format org-e-latex-inactive-timestamp-format
- (org-translate-time range-end))))
- (otherwise (format org-e-latex-diary-timestamp-format value)))))
-
-
-;;;; Underline
-
-(defun org-e-latex-underline (underline contents info)
- "Transcode UNDERLINE from Org to LaTeX.
-CONTENTS is the text with underline markup. INFO is a plist
-holding contextual information."
- (org-e-latex--text-markup contents 'underline))
-
-
-;;;; Verbatim
-
-(defun org-e-latex-verbatim (verbatim contents info)
- "Transcode a VERBATIM object from Org to LaTeX.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (org-e-latex--text-markup (org-element-property :value verbatim) 'verbatim))
-
-
-;;;; Verse Block
-
-(defun org-e-latex-verse-block (verse-block contents info)
- "Transcode a VERSE-BLOCK element from Org to LaTeX.
-CONTENTS is verse block contents. INFO is a plist holding
-contextual information."
- (org-e-latex--wrap-label
- verse-block
- ;; In a verse environment, add a line break to each newline
- ;; character and change each white space at beginning of a line
- ;; into a space of 1 em. Also change each blank line with
- ;; a vertical space of 1 em.
- (progn
- (setq contents (replace-regexp-in-string
- "^ *\\\\\\\\$" "\\\\vspace*{1em}"
- (replace-regexp-in-string
- "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n" contents)))
- (while (string-match "^[ \t]+" contents)
- (let ((new-str (format "\\hspace*{%dem}"
- (length (match-string 0 contents)))))
- (setq contents (replace-match new-str nil t contents))))
- (format "\\begin{verse}\n%s\\end{verse}" contents))))
-
-
-
-;;; Interactive functions
-
-;;;###autoload
-(defun org-e-latex-export-as-latex
- (&optional subtreep visible-only body-only ext-plist)
- "Export current buffer as a LaTeX buffer.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-Export is done in a buffer named \"*Org E-LATEX Export*\", which
-will be displayed when `org-export-show-temporary-export-buffer'
-is non-nil."
- (interactive)
- (let ((outbuf (org-export-to-buffer
- 'e-latex "*Org E-LATEX Export*"
- subtreep visible-only body-only ext-plist)))
- (with-current-buffer outbuf (LaTeX-mode))
- (when org-export-show-temporary-export-buffer
- (switch-to-buffer-other-window outbuf))))
-
-;;;###autoload
-(defun org-e-latex-export-to-latex
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to a LaTeX file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (let ((outfile (org-export-output-file-name ".tex" subtreep pub-dir)))
- (org-export-to-file
- 'e-latex outfile subtreep visible-only body-only ext-plist)))
-
-;;;###autoload
-(defun org-e-latex-export-to-pdf
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to LaTeX then process through to PDF.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return PDF file's name."
- (interactive)
- (org-e-latex-compile
- (org-e-latex-export-to-latex
- subtreep visible-only body-only ext-plist pub-dir)))
-
-(defun org-e-latex-compile (texfile)
- "Compile a TeX file.
-
-TEXFILE is the name of the file being compiled. Processing is
-done through the command specified in `org-e-latex-pdf-process'.
-
-Return PDF file name or an error if it couldn't be produced."
- (let* ((wconfig (current-window-configuration))
- (texfile (file-truename texfile))
- (base (file-name-sans-extension texfile))
- errors)
- (message (format "Processing LaTeX file %s ..." texfile))
- (unwind-protect
- (progn
- (cond
- ;; A function is provided: Apply it.
- ((functionp org-e-latex-pdf-process)
- (funcall org-e-latex-pdf-process (shell-quote-argument texfile)))
- ;; A list is provided: Replace %b, %f and %o with appropriate
- ;; values in each command before applying it. Output is
- ;; redirected to "*Org PDF LaTeX Output*" buffer.
- ((consp org-e-latex-pdf-process)
- (let* ((out-dir (or (file-name-directory texfile) "./"))
- (outbuf (get-buffer-create "*Org PDF LaTeX Output*")))
- (mapc
- (lambda (command)
- (shell-command
- (replace-regexp-in-string
- "%b" (shell-quote-argument base)
- (replace-regexp-in-string
- "%f" (shell-quote-argument texfile)
- (replace-regexp-in-string
- "%o" (shell-quote-argument out-dir) command t t) t t) t t)
- outbuf))
- org-e-latex-pdf-process)
- ;; Collect standard errors from output buffer.
- (setq errors (org-e-latex--collect-errors outbuf))))
- (t (error "No valid command to process to PDF")))
- (let ((pdffile (concat base ".pdf")))
- ;; Check for process failure. Provide collected errors if
- ;; possible.
- (if (not (file-exists-p pdffile))
- (error (concat (format "PDF file %s wasn't produced" pdffile)
- (when errors (concat ": " errors))))
- ;; Else remove log files, when specified, and signal end of
- ;; process to user, along with any error encountered.
- (when org-e-latex-remove-logfiles
- (dolist (ext org-e-latex-logfiles-extensions)
- (let ((file (concat base "." ext)))
- (when (file-exists-p file) (delete-file file)))))
- (message (concat "Process completed"
- (if (not errors) "."
- (concat " with errors: " errors)))))
- ;; Return output file name.
- pdffile))
- (set-window-configuration wconfig))))
-
-(defun org-e-latex--collect-errors (buffer)
- "Collect some kind of errors from \"pdflatex\" command output.
-
-BUFFER is the buffer containing output.
-
-Return collected error types as a string, or nil if there was
-none."
- (with-current-buffer buffer
- (save-excursion
- (goto-char (point-max))
- ;; Find final "pdflatex" run.
- (when (re-search-backward "^[ \t]*This is pdf.*?TeX.*?Version" nil t)
- (let ((case-fold-search t)
- (errors ""))
- (when (save-excursion
- (re-search-forward "Reference.*?undefined" nil t))
- (setq errors (concat errors " [undefined reference]")))
- (when (save-excursion
- (re-search-forward "Citation.*?undefined" nil t))
- (setq errors (concat errors " [undefined citation]")))
- (when (save-excursion
- (re-search-forward "Undefined control sequence" nil t))
- (setq errors (concat errors " [undefined control sequence]")))
- (when (save-excursion
- (re-search-forward "^! LaTeX.*?Error" nil t))
- (setq errors (concat errors " [LaTeX error]")))
- (when (save-excursion
- (re-search-forward "^! Package.*?Error" nil t))
- (setq errors (concat errors " [package error]")))
- (and (org-string-nw-p errors) (org-trim errors)))))))
-
-
-(provide 'org-e-latex)
-;;; org-e-latex.el ends here
diff --git a/contrib/lisp/org-e-man.el b/contrib/lisp/org-e-man.el
deleted file mode 100644
index 981f831..0000000
--- a/contrib/lisp/org-e-man.el
+++ /dev/null
@@ -1,1363 +0,0 @@
-;; org-e-man.el --- Man Back-End For Org Export Engine
-
-;; Copyright (C) 2011-2012 Free Software Foundation, Inc.
-
-;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
-;; Author: Luis R Anaya <papoanaya aroba hot mail punto com>
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; This library implements a Man back-end for Org generic exporter.
-;;
-;; To test it, run
-;;
-;; M-: (org-export-to-buffer 'e-man "*Test e-Man*") RET
-;;
-;; in an org-mode buffer then switch to the buffer to see the Man
-;; export. See contrib/lisp/org-export.el for more details on how
-;; this exporter works.
-;;
-;; It introduces one new buffer keywords:
-;; "MAN_CLASS_OPTIONS".
-
-;;;; Code:
-
-(require 'org-export)
-
-(eval-when-compile (require 'cl))
-
-(defvar org-export-man-default-packages-alist)
-(defvar org-export-man-packages-alist)
-
-
-
-
-
-
-;;;; Define Back-End
-
-(defvar org-e-man-translate-alist
- '((babel-call . org-e-man-babel-call)
- (bold . org-e-man-bold)
- (center-block . org-e-man-center-block)
- (clock . org-e-man-clock)
- (code . org-e-man-code)
- (comment . org-e-man-comment)
- (comment-block . org-e-man-comment-block)
- (drawer . org-e-man-drawer)
- (dynamic-block . org-e-man-dynamic-block)
- (entity . org-e-man-entity)
- (example-block . org-e-man-example-block)
- (export-block . org-e-man-export-block)
- (export-snippet . org-e-man-export-snippet)
- (fixed-width . org-e-man-fixed-width)
- (footnote-definition . org-e-man-footnote-definition)
- (footnote-reference . org-e-man-footnote-reference)
- (headline . org-e-man-headline)
- (horizontal-rule . org-e-man-horizontal-rule)
- (inline-babel-call . org-e-man-inline-babel-call)
- (inline-src-block . org-e-man-inline-src-block)
- (inlinetask . org-e-man-inlinetask)
- (italic . org-e-man-italic)
- (item . org-e-man-item)
- (keyword . org-e-man-keyword)
- (man-environment . org-e-man-man-environment)
- (man-fragment . org-e-man-man-fragment)
- (line-break . org-e-man-line-break)
- (link . org-e-man-link)
- (macro . org-e-man-macro)
- (paragraph . org-e-man-paragraph)
- (plain-list . org-e-man-plain-list)
- (plain-text . org-e-man-plain-text)
- (planning . org-e-man-planning)
- (property-drawer . org-e-man-property-drawer)
- (quote-block . org-e-man-quote-block)
- (quote-section . org-e-man-quote-section)
- (radio-target . org-e-man-radio-target)
- (section . org-e-man-section)
- (special-block . org-e-man-special-block)
- (src-block . org-e-man-src-block)
- (statistics-cookie . org-e-man-statistics-cookie)
- (strike-through . org-e-man-strike-through)
- (subscript . org-e-man-subscript)
- (superscript . org-e-man-superscript)
- (table . org-e-man-table)
- (table-cell . org-e-man-table-cell)
- (table-row . org-e-man-table-row)
- (target . org-e-man-target)
- (template . org-e-man-template)
- (timestamp . org-e-man-timestamp)
- (underline . org-e-man-underline)
- (verbatim . org-e-man-verbatim)
- (verse-block . org-e-man-verse-block))
- "Alist between element or object types and translators.")
-
-(defconst org-e-man-options-alist
- '((:date "DATE" nil nil t)
- (:man-class "MAN_CLASS" nil nil t)
- (:man-class-options "MAN_CLASS_OPTIONS" nil nil t)
- (:man-header-extra "MAN_HEADER" nil nil newline))
- "Alist between Man export properties and ways to set them.
-See `org-export-options-alist' for more information on the
-structure of the values.")
-
-
-
-
-;;; User Configurable Variables
-
-
-(defgroup org-export-e-man nil
- "Options for exporting Org mode files to Man."
- :tag "Org Export Man"
- :group 'org-export)
-
-
-;;;; Tables
-
-
-(defcustom org-e-man-tables-centered t
- "When non-nil, tables are exported in a center environment."
- :group 'org-export-e-man
- :type 'boolean)
-
-(defcustom org-e-man-tables-verbatim nil
- "When non-nil, tables are exported verbatim."
- :group 'org-export-e-man
- :type 'boolean)
-
-(defcustom org-e-man-table-scientific-notation "%sE%s"
- "Format string to display numbers in scientific notation.
-The format should have \"%s\" twice, for mantissa and exponent
-\(i.e. \"%s\\\\times10^{%s}\").
-
-When nil, no transformation is made."
- :group 'org-export-e-man
- :type '(choice
- (string :tag "Format string")
- (const :tag "No formatting")))
-
-
-;;;; Inlinetasks
-
-
-;; Src blocks
-
-(defcustom org-e-man-source-highlight nil
- "Use GNU source highlight to embellish source blocks "
- :group 'org-export-e-man
- :type 'boolean)
-
-(defcustom org-e-man-source-highlight-langs
- '((emacs-lisp "lisp") (lisp "lisp") (clojure "lisp")
- (scheme "scheme")
- (c "c") (cc "cpp") (csharp "csharp") (d "d")
- (fortran "fortran") (cobol "cobol") (pascal "pascal")
- (ada "ada") (asm "asm")
- (perl "perl") (cperl "perl")
- (python "python") (ruby "ruby") (tcl "tcl") (lua "lua")
- (java "java") (javascript "javascript")
- (tex "latex")
- (shell-script "sh") (awk "awk") (diff "diff") (m4 "m4")
- (ocaml "caml") (caml "caml")
- (sql "sql") (sqlite "sql")
- (html "html") (css "css") (xml "xml")
- (bat "bat") (bison "bison") (clipper "clipper")
- (ldap "ldap") (opa "opa")
- (php "php") (postscript "postscript") (prolog "prolog")
- (properties "properties") (makefile "makefile")
- (tml "tml") (vala "vala") (vbscript "vbscript") (xorg "xorg"))
- "Alist mapping languages to their listing language counterpart.
-The key is a symbol, the major mode symbol without the \"-mode\".
-The value is the string that should be inserted as the language
-parameter for the listings package. If the mode name and the
-listings name are the same, the language does not need an entry
-in this list - but it does not hurt if it is present."
- :group 'org-export-e-man
- :type '(repeat
- (list
- (symbol :tag "Major mode ")
- (string :tag "Listings language"))))
-
-
-(defvar org-e-man-custom-lang-environments nil
- "Alist mapping languages to language-specific Man environments.
-
-It is used during export of src blocks by the listings and
-man packages. For example,
-
- \(setq org-e-man-custom-lang-environments
- '\(\(python \"pythoncode\"\)\)\)
-
-would have the effect that if org encounters begin_src python
-during man export."
-)
-
-
-;;;; Plain text
-
-(defcustom org-e-man-quotes
- '(("fr"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "«~")
- ("\\(\\S-\\)\"" . "~»")
- ("\\(\\s-\\|(\\|^\\)'" . "'"))
- ("en"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "``")
- ("\\(\\S-\\)\"" . "''")
- ("\\(\\s-\\|(\\|^\\)'" . "`")))
-
- "Alist for quotes to use when converting english double-quotes.
-
-The CAR of each item in this alist is the language code.
-The CDR of each item in this alist is a list of three CONS:
-- the first CONS defines the opening quote;
-- the second CONS defines the closing quote;
-- the last CONS defines single quotes.
-
-For each item in a CONS, the first string is a regexp
-for allowed characters before/after the quote, the second
-string defines the replacement string for this quote."
- :group 'org-export-e-man
- :type '(list
- (cons :tag "Opening quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))
- (cons :tag "Closing quote"
- (string :tag "Regexp for char after ")
- (string :tag "Replacement quote "))
- (cons :tag "Single quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))))
-
-
-;;;; Compilation
-
-(defcustom org-e-man-pdf-process
- '("tbl %f | eqn | groff -man | ps2pdf - > %b.pdf"
- "tbl %f | eqn | groff -man | ps2pdf - > %b.pdf"
- "tbl %f | eqn | groff -man | ps2pdf - > %b.pdf")
-
- "Commands to process a Man file to a PDF file.
-This is a list of strings, each of them will be given to the
-shell as a command. %f in the command will be replaced by the
-full file name, %b by the file base name \(i.e. without
-extension) and %o by the base directory of the file.
-
-
-By default, Org uses 3 runs of to do the processing.
-
-Alternatively, this may be a Lisp function that does the
-processing. This function should accept the file name as
-its single argument."
- :group 'org-export-pdf
- :type '(choice
- (repeat :tag "Shell command sequence"
- (string :tag "Shell command"))
- (const :tag "2 runs of pdfgroff"
- ("tbl %f | eqn | groff -mm | ps2pdf - > %b.pdf"
- "tbl %f | eqn | groff -mm | ps2pdf - > %b.pdf"))
- (const :tag "3 runs of pdfgroff"
- ("tbl %f | eqn | groff -mm | ps2pdf - > %b.pdf"
- "tbl %f | eqn | groff -mm | ps2pdf - > %b.pdf"
- "tbl %f | eqn | groff -mm | ps2pdf - > %b.pdf"))
- (function)))
-
-(defcustom org-e-man-logfiles-extensions
- '("log" "out" "toc")
- "The list of file extensions to consider as Man logfiles."
- :group 'org-export-e-man
- :type '(repeat (string :tag "Extension")))
-
-(defcustom org-e-man-remove-logfiles t
- "Non-nil means remove the logfiles produced by PDF production.
-These are the .aux, .log, .out, and .toc files."
- :group 'org-export-e-man
- :type 'boolean)
-
-
-
-;; Preamble
-
-
-;; Adding MAN as a block parser to make sure that its contents
-;; does not execute
-
-(add-to-list 'org-element-block-name-alist
- '("MAN" . org-element-export-block-parser))
-
-
-
-
-
-;;; Internal Functions
-
-(defun org-e-man--caption/label-string (caption label info)
- "Return caption and label Man string for floats.
-
-CAPTION is a cons cell of secondary strings, the car being the
-standard caption and the cdr its short form. LABEL is a string
-representing the label. INFO is a plist holding contextual
-information.
-
-If there's no caption nor label, return the empty string.
-
-For non-floats, see `org-e-man--wrap-label'."
- (let ((label-str ""))
- (cond
- ((and (not caption) (not label)) "")
- ((not caption) (format "\\fI%s\\fP" label))
- ;; Option caption format with short name.
- ((cdr caption)
- (format "\\fR%s\\fP - \\fI%s\\P - %s\n"
- (org-export-data (cdr caption) info)
- label-str
- (org-export-data (car caption) info)))
- ;; Standard caption format.
- (t (format "\\fR%s\\fP"
- (org-export-data (car caption) info))))))
-
-(defun org-e-man--quotation-marks (text info)
- "Export quotation marks depending on language conventions.
-TEXT is a string containing quotation marks to be replaced. INFO
-is a plist used as a communication channel."
- (mapc (lambda(l)
- (let ((start 0))
- (while (setq start (string-match (car l) text start))
- (let ((new-quote (concat (match-string 1 text) (cdr l))))
- (setq text (replace-match new-quote t t text))))))
- (cdr (or (assoc (plist-get info :language) org-e-man-quotes)
- ;; Falls back on English.
- (assoc "en" org-e-man-quotes))))
- text)
-
-(defun org-e-man--wrap-label (element output)
- "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
-This function shouldn't be used for floats. See
-`org-e-man--caption/label-string'."
- (let ((label (org-element-property :name element)))
- (if (or (not output) (not label) (string= output "") (string= label ""))
- output
- (concat (format "%s\n.br\n" label) output))))
-
-
-
-
-;;; Template
-
-(defun org-e-man-template (contents info)
- "Return complete document string after Man conversion.
-CONTENTS is the transcoded contents string. INFO is a plist
-holding export options."
- (let* ((title (org-export-data (plist-get info :title) info))
- (attr
- (read (format "(%s)"
- (mapconcat
- #'identity
- (list (plist-get info :man-class-options))
- " "))))
- (section-item (plist-get attr :section-id)))
-
- (concat
- (cond
- ((and title (stringp section-item))
- (format ".TH \"%s\" \"%s\" \n" title section-item))
- ((and (string= "" title) (stringp section-item))
- (format ".TH \"%s\" \"%s\" \n" " " section-item))
- (title
- (format ".TH \"%s\" \"1\" \n" title))
- (t
- ".TH \" \" \"1\" "))
- contents)))
-
-
-
-
-;;; Transcode Functions
-
-;;;; Babel Call
-
-;; Babel Calls are ignored.
-
-
-;;;; Bold
-
-(defun org-e-man-bold (bold contents info)
- "Transcode BOLD from Org to Man.
-CONTENTS is the text with bold markup. INFO is a plist holding
-contextual information."
- (format "\\fB%s\\fP" contents))
-
-
-;;;; Center Block
-
-(defun org-e-man-center-block (center-block contents info)
- "Transcode a CENTER-BLOCK element from Org to Man.
-CONTENTS holds the contents of the center block. INFO is a plist
-holding contextual information."
- (org-e-man--wrap-label
- center-block
- (format ".ce %d\n.nf\n%s\n.fi"
- (- (length (split-string contents "\n")) 1)
- contents)))
-
-
-;;;; Clock
-
-(defun org-e-man-clock (clock contents info)
- "Transcode a CLOCK element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- "")
-
-
-;;;; Code
-
-(defun org-e-man-code (code contents info)
- "Transcode a CODE object from Org to Man.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (format "\\fC%s\\fP" code))
-
-
-;;;; Comment
-;; Comments are ignored.
-
-
-;;;; Comment Block
-;; Comment Blocks are ignored.
-
-
-;;;; Drawer
-
-(defun org-e-man-drawer (drawer contents info)
- "Transcode a DRAWER element from Org to Man.
- DRAWER holds the drawer information
- CONTENTS holds the contents of the block.
- INFO is a plist holding contextual information. "
- contents)
-
-
-;;;; Dynamic Block
-
-(defun org-e-man-dynamic-block (dynamic-block contents info)
- "Transcode a DYNAMIC-BLOCK element from Org to Man.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information. See `org-export-data'."
- (org-e-man--wrap-label dynamic-block contents))
-
-
-;;;; Entity
-
-(defun org-e-man-entity (entity contents info)
- "Transcode an ENTITY object from Org to Man.
-CONTENTS are the definition itself. INFO is a plist holding
-contextual information."
- (let ((ent (org-element-property :utf8 entity))) ent))
-
-
-;;;; Example Block
-
-(defun org-e-man-example-block (example-block contents info)
- "Transcode an EXAMPLE-BLOCK element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (org-e-man--wrap-label
- example-block
- (format ".RS\n.nf\n%s\n.fi\n.RE"
- (org-export-format-code-default example-block info))))
-
-;;;; Export Block
-
-(defun org-e-man-export-block (export-block contents info)
- "Transcode a EXPORT-BLOCK element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (string= (org-element-property :type export-block) "MAN")
- (org-remove-indentation (org-element-property :value export-block))))
-
-
-;;;; Export Snippet
-
-(defun org-e-man-export-snippet (export-snippet contents info)
- "Transcode a EXPORT-SNIPPET object from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (eq (org-export-snippet-backend export-snippet) 'e-man)
- (org-element-property :value export-snippet)))
-
-
-;;;; Fixed Width
-
-(defun org-e-man-fixed-width (fixed-width contents info)
- "Transcode a FIXED-WIDTH element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-man--wrap-label
- fixed-width
- (format "\\fC\n%s\\fP"
- (org-remove-indentation
- (org-element-property :value fixed-width)))))
-
-
-;;;; Footnote Definition
-;; Footnote Definitions are ignored.
-
-;;;; Footnote References
-;; Footnote References are Ignored
-
-
-;;;; Headline
-
-(defun org-e-man-headline (headline contents info)
- "Transcode an HEADLINE element from Org to Man.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- (let* ((level (org-export-get-relative-level headline info))
- (numberedp (org-export-numbered-headline-p headline info))
- ;; Section formatting will set two placeholders: one for the
- ;; title and the other for the contents.
- (section-fmt
- (case level
- (1 ".SH \"%s\"\n%s")
- (2 ".SS \"%s\"\n%s")
- (3 ".SS \"%s\"\n%s")
- (t nil)))
- (text (org-export-data (org-element-property :title headline) info)))
-
- (cond
- ;; Case 1: This is a footnote section: ignore it.
- ((org-element-property :footnote-section-p headline) nil)
-
- ;; Case 2. This is a deep sub-tree: export it as a list item.
- ;; Also export as items headlines for which no section
- ;; format has been found.
- ((or (not section-fmt) (org-export-low-level-p headline info))
- ;; Build the real contents of the sub-tree.
- (let ((low-level-body
- (concat
- ;; If the headline is the first sibling, start a list.
- (when (org-export-first-sibling-p headline info)
- (format "%s\n" ".RS"))
- ;; Itemize headline
- ".TP\n.ft I\n" text "\n.ft\n"
- contents ".RE")))
- ;; If headline is not the last sibling simply return
- ;; LOW-LEVEL-BODY. Otherwise, also close the list, before any
- ;; blank line.
- (if (not (org-export-last-sibling-p headline info)) low-level-body
- (replace-regexp-in-string
- "[ \t\n]*\\'" ""
- low-level-body))))
-
- ;; Case 3. Standard headline. Export it as a section.
- (t (format section-fmt text contents)))))
-
-
-;;;; Horizontal Rule
-;; Not supported
-
-
-;;;; Inline Babel Call
-;; Inline Babel Calls are ignored.
-
-
-;;;; Inline Src Block
-
-(defun org-e-man-inline-src-block (inline-src-block contents info)
- "Transcode an INLINE-SRC-BLOCK element from Org to Man.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((code (org-element-property :value inline-src-block)))
- (cond
- (org-e-man-source-highlight
- (let* ((tmpdir (if (featurep 'xemacs)
- temp-directory
- temporary-file-directory))
- (in-file (make-temp-name
- (expand-file-name "srchilite" tmpdir)))
- (out-file (make-temp-name
- (expand-file-name "reshilite" tmpdir)))
- (org-lang (org-element-property :language inline-src-block))
- (lst-lang (cadr (assq (intern org-lang)
- org-e-man-source-highlight-langs)))
-
- (cmd (concat (expand-file-name "source-highlight")
- " -s " lst-lang
- " -f groff_man"
- " -i " in-file
- " -o " out-file)))
-
- (if lst-lang
- (let ((code-block ""))
- (with-temp-file in-file (insert code))
- (shell-command cmd)
- (setq code-block (org-file-contents out-file))
- (delete-file in-file)
- (delete-file out-file)
- code-block)
- (format ".RS\n.nf\n\\fC\\m[black]%s\\m[]\\fP\n.fi\n.RE\n"
- code))))
-
- ;; Do not use a special package: transcode it verbatim.
- (t
- (concat ".RS\n.nf\n" "\\fC" "\n" code "\n"
- "\\fP\n.fi\n.RE\n")))))
-
-
-;;;; Inlinetask
-;;;; Italic
-
-(defun org-e-man-italic (italic contents info)
- "Transcode ITALIC from Org to Man.
-CONTENTS is the text with italic markup. INFO is a plist holding
-contextual information."
- (format "\\fI%s\\fP" contents))
-
-
-;;;; Item
-
-(defun org-e-man-item (item contents info)
-
- "Transcode an ITEM element from Org to Man.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
-
- (let* ((bullet (org-element-property :bullet item))
- (type (org-element-property :type (org-element-property :parent item)))
- (checkbox (case (org-element-property :checkbox item)
- (on "\\o'\\(sq\\(mu'") ;;
- (off "\\(sq ") ;;
- (trans "\\o'\\(sq\\(mi'"))) ;;
-
- (tag (let ((tag (org-element-property :tag item)))
- ;; Check-boxes must belong to the tag.
- (and tag (format "\\fB%s\\fP"
- (concat checkbox
- (org-export-data tag info)))))))
-
- (if (and (null tag)
- (null checkbox))
- (let* ((bullet (org-trim bullet))
- (marker (cond ((string= "-" bullet) "\\(em")
- ((string= "*" bullet) "\\(bu")
- ((eq type 'ordered)
- (format "%s " (org-trim bullet)))
- (t "\\(dg"))))
- (concat ".IP " marker " 4\n"
- (org-trim (or contents " "))))
- ; else
- (concat ".TP\n" (or tag (concat " " checkbox)) "\n"
- (org-trim (or contents " "))))))
-
-
-;;;; Keyword
-
-(defun org-e-man-keyword (keyword contents info)
- "Transcode a KEYWORD element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((key (org-element-property :key keyword))
- (value (org-element-property :value keyword)))
- (cond
- ((string= key "MAN") value)
- ((string= key "INDEX") nil)
- ;; Invisible targets.
- ((string= key "TARGET") nil)
- ((string= key "TOC") nil))))
-
-
-;;;; Man Environment
-
-(defun org-e-man-man-environment (man-environment contents info)
- "Transcode a MAN-ENVIRONMENT element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((label (org-element-property :name man-environment))
- (value (org-remove-indentation
- (org-element-property :value man-environment))))
- (if (not (org-string-nw-p label)) value
- ;; Environment is labelled: label must be within the environment
- ;; (otherwise, a reference pointing to that element will count
- ;; the section instead).
- (with-temp-buffer
- (insert value)
- (goto-char (point-min))
- (forward-line)
- (insert (format "%s\n" label))
- (buffer-string)))))
-
-
-;;;; Man Fragment
-
-(defun org-e-man-man-fragment (man-fragment contents info)
- "Transcode a MAN-FRAGMENT object from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-element-property :value man-fragment))
-
-
-;;;; Line Break
-
-(defun org-e-man-line-break (line-break contents info)
- "Transcode a LINE-BREAK object from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- ".br\n")
-
-
-;;;; Link
-
-(defun org-e-man-link (link desc info)
- "Transcode a LINK object from Org to Man.
-
-DESC is the description part of the link, or the empty string.
-INFO is a plist holding contextual information. See
-`org-export-data'."
-
- (let* ((type (org-element-property :type link))
- (raw-path (org-element-property :path link))
- ;; Ensure DESC really exists, or set it to nil.
- (desc (and (not (string= desc "")) desc))
-
- (path (cond
- ((member type '("http" "https" "ftp" "mailto"))
- (concat type ":" raw-path))
- ((string= type "file")
- (when (string-match "\\(.+\\)::.+" raw-path)
- (setq raw-path (match-string 1 raw-path)))
- (if (file-name-absolute-p raw-path)
- (concat "file://" (expand-file-name raw-path))
- (concat "file://" raw-path)))
- (t raw-path)))
- protocol)
- (cond
- ;; External link with a description part.
- ((and path desc) (format "%s \\fBat\\fP \\fI%s\\fP" path desc))
- ;; External link without a description part.
- (path (format "\\fI%s\\fP" path))
- ;; No path, only description. Try to do something useful.
- (t (format "\\fI%s\\fP" desc)))))
-
-
-;;;; Macro
-
-(defun org-e-man-macro (macro contents info)
- "Transcode a MACRO element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- ;; Use available tools.
- (org-export-expand-macro macro info))
-
-
-;;;; Paragraph
-
-(defun org-e-man-paragraph (paragraph contents info)
- "Transcode a PARAGRAPH element from Org to Man.
-CONTENTS is the contents of the paragraph, as a string. INFO is
-the plist used as a communication channel."
- (let ((parent (plist-get (nth 1 paragraph) :parent)))
- (when parent
- (let ((parent-type (car parent))
- (fixed-paragraph ""))
- (cond ((and (eq parent-type 'item)
- (plist-get (nth 1 parent) :bullet))
- (setq fixed-paragraph (concat "" contents)))
- ((eq parent-type 'section)
- (setq fixed-paragraph (concat ".PP\n" contents)))
- ((eq parent-type 'footnote-definition)
- (setq fixed-paragraph contents))
- (t (setq fixed-paragraph (concat "" contents))))
- fixed-paragraph))))
-
-
-;;;; Plain List
-
-(defun org-e-man-plain-list (plain-list contents info)
- "Transcode a PLAIN-LIST element from Org to Man.
-CONTENTS is the contents of the list. INFO is a plist holding
-contextual information."
- contents)
-
-
-;;;; Plain Text
-
-(defun org-e-man-plain-text (text info)
- "Transcode a TEXT string from Org to Man.
-TEXT is the string to transcode. INFO is a plist holding
-contextual information."
- ;; Protect
- (setq text (replace-regexp-in-string
- "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
- "$\\" text nil t 1))
-
- ;; Handle quotation marks
- (setq text (org-e-man--quotation-marks text info))
-
- ;; Handle break preservation if required.
-
- (when (plist-get info :preserve-breaks)
- (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
- text)))
- ;; Return value.
- text)
-
-
-;;;; Planning
-
-;;;; Property Drawer
-
-
-;;;; Quote Block
-
-(defun org-e-man-quote-block (quote-block contents info)
- "Transcode a QUOTE-BLOCK element from Org to Man.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (org-e-man--wrap-label
- quote-block
- (format ".RS\n%s\n.RE" contents)))
-
-
-;;;; Quote Section
-
-(defun org-e-man-quote-section (quote-section contents info)
- "Transcode a QUOTE-SECTION element from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((value (org-remove-indentation
- (org-element-property :value quote-section))))
- (when value (format ".RS\\fI%s\\fP\n.RE\n" value))))
-
-
-;;;; Radio Target
-
-(defun org-e-man-radio-target (radio-target text info)
- "Transcode a RADIO-TARGET object from Org to Man.
-TEXT is the text of the target. INFO is a plist holding
-contextual information."
- text)
-
-
-;;;; Section
-
-(defun org-e-man-section (section contents info)
- "Transcode a SECTION element from Org to Man.
-CONTENTS holds the contents of the section. INFO is a plist
-holding contextual information."
- contents)
-
-
-;;;; Special Block
-
-(defun org-e-man-special-block (special-block contents info)
- "Transcode a SPECIAL-BLOCK element from Org to Man.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((type (downcase (org-element-property :type special-block))))
- (org-e-man--wrap-label
- special-block
- (format "%s\n" contents))))
-
-
-;;;; Src Block
-
-(defun org-e-man-src-block (src-block contents info)
- "Transcode a SRC-BLOCK element from Org to Man.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
-
- (let* ((lang (org-element-property :language src-block))
- (caption (org-element-property :caption src-block))
- (label (org-element-property :name src-block))
- (code (org-element-property :value src-block))
- (custom-env (and lang
- (cadr (assq (intern lang)
- org-e-man-custom-lang-environments))))
- (num-start (case (org-element-property :number-lines src-block)
- (continued (org-export-get-loc src-block info))
- (new 0)))
- (retain-labels (org-element-property :retain-labels src-block)))
- (cond
- ;; Case 1. No source fontification.
- ((not org-e-man-source-highlight)
- (let ((caption-str (org-e-man--caption/label-string caption label info)))
- (concat
- (format ".RS\n.nf\n\\fC%s\\fP\n.fi\n.RE\n\n"
- (org-export-format-code-default src-block info)))))
- ((and org-e-man-source-highlight)
- (let* ((tmpdir (if (featurep 'xemacs)
- temp-directory
- temporary-file-directory))
-
- (in-file (make-temp-name
- (expand-file-name "srchilite" tmpdir)))
- (out-file (make-temp-name
- (expand-file-name "reshilite" tmpdir)))
-
- (org-lang (org-element-property :language src-block))
- (lst-lang (cadr (assq (intern org-lang)
- org-e-man-source-highlight-langs)))
-
- (cmd (concat "source-highlight"
- " -s " lst-lang
- " -f groff_man "
- " -i " in-file
- " -o " out-file)))
-
- (if lst-lang
- (let ((code-block ""))
- (with-temp-file in-file (insert code))
- (shell-command cmd)
- (setq code-block (org-file-contents out-file))
- (delete-file in-file)
- (delete-file out-file)
- code-block)
- (format ".RS\n.nf\n\\fC\\m[black]%s\\m[]\\fP\n.fi\n.RE"
- code)))))))
-
-
-;;;; Statistics Cookie
-
-(defun org-e-man-statistics-cookie (statistics-cookie contents info)
- "Transcode a STATISTICS-COOKIE object from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-element-property :value statistics-cookie))
-
-
-;;;; Strike-Through
-
-(defun org-e-man-strike-through (strike-through contents info)
- "Transcode STRIKE-THROUGH from Org to Man.
-CONTENTS is the text with strike-through markup. INFO is a plist
-holding contextual information."
- (format "\\fI%s\\fP" contents))
-
-
-;;;; Subscript
-
-(defun org-e-man-subscript (subscript contents info)
- "Transcode a SUBSCRIPT object from Org to Man.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "\\d\\s-2%s\\s+2\\u" contents))
-
-
-;;;; Superscript "^_%s$
-
-(defun org-e-man-superscript (superscript contents info)
- "Transcode a SUPERSCRIPT object from Org to Man.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "\\u\\s-2%s\\s+2\\d" contents))
-
-
-;;;; Table
-;;
-;; `org-e-man-table' is the entry point for table transcoding. It
-;; takes care of tables with a "verbatim" attribute. Otherwise, it
-;; delegates the job to either `org-e-man-table--table.el-table' or
-;; `org-e-man-table--org-table' functions, depending of the type of
-;; the table.
-;;
-;; `org-e-man-table--align-string' is a subroutine used to build
-;; alignment string for Org tables.
-
-(defun org-e-man-table (table contents info)
- "Transcode a TABLE element from Org to Man.
-CONTENTS is the contents of the table. INFO is a plist holding
-contextual information."
- (cond
- ;; Case 1: verbatim table.
- ((or org-e-man-tables-verbatim
- (let ((attr
- (read
- (format
- "(%s)"
- (mapconcat
- #'identity
- (org-element-property :attr_man table)
- " ")))))
-
- (and attr (plist-get attr :verbatim))))
-
- (format ".nf\n\\fC%s\\fP\n.fi"
- ;; Re-create table, without affiliated keywords.
- (org-trim
- (org-element-interpret-data
- `(table nil ,@(org-element-contents table))))))
- ;; Case 2: Standard table.
- (t (org-e-man-table--org-table table contents info))))
-
-(defun org-e-man-table--align-string (divider table info)
- "Return an appropriate Man alignment string.
-TABLE is the considered table. INFO is a plist used as
-a communication channel."
-(let (alignment)
- ;; Extract column groups and alignment from first (non-rule)
- ;; row.
- (org-element-map
- (org-element-map
- table 'table-row
- (lambda (row)
- (and (eq (org-element-property :type row) 'standard) row))
- info 'first-match)
- 'table-cell
- (lambda (cell)
- (let* ((borders (org-export-table-cell-borders cell info))
- (raw-width (org-export-table-cell-width cell info))
- (width-cm (when raw-width (/ raw-width 5)))
- (width (if raw-width (format "w(%dc)"
- (if (< width-cm 1) 1 width-cm)) "")))
- ;; Check left border for the first cell only.
- (when (and (memq 'left borders) (not alignment))
- (push "|" alignment))
- (push
- (case (org-export-table-cell-alignment cell info)
- (left (concat "l" width divider))
- (right (concat "r" width divider))
- (center (concat "c" width divider)))
- alignment)
- (when (memq 'right borders) (push "|" alignment))))
- info)
- (apply 'concat (reverse alignment))))
-
-(defun org-e-man-table--org-table (table contents info)
- "Return appropriate Man code for an Org table.
-
-TABLE is the table type element to transcode. CONTENTS is its
-contents, as a string. INFO is a plist used as a communication
-channel.
-
-This function assumes TABLE has `org' as its `:type' attribute."
- (let* ((label (org-element-property :name table))
- (caption (org-e-man--caption/label-string
- (org-element-property :caption table) label info))
- (attr
- (read
- (format
- "(%s)"
- (mapconcat
- #'identity
- (org-element-property :attr_man table)
- " "))))
-
- (divider (if (plist-get attr :divider)
- "|"
- " "))
-
- ;; Determine alignment string.
- (alignment (org-e-man-table--align-string divider table info))
- ;; Extract others display options.
- (lines (org-split-string contents "\n"))
-
- (attr-list
- (let ((result-list '()))
- (dolist (attr-item
- (list
- (if (plist-get attr :expand)
- "expand"
- nil)
-
- (case (plist-get attr :placement)
- ('center "center")
- ('left nil)
- (t
- (if org-e-man-tables-centered
- "center" "")))
-
- (case (plist-get attr :boxtype)
- ('box "box")
- ('doublebox "doublebox")
- ('allbox "allbox")
- ('none nil)
- (t "box"))))
-
- (if attr-item
- (add-to-list 'result-list attr-item)))
- result-list))
-
-
- (title-line (plist-get attr :title-line))
-
- (table-format
- (concat
- (format "%s"
- (or (car attr-list) ""))
- (or
- (let ((output-list '()))
- (when (cdr attr-list)
- (dolist (attr-item (cdr attr-list))
- (setq output-list (concat output-list (format ",%s" attr-item)))))
- output-list)
- "")))
-
- (first-line
- (when lines (org-split-string (car lines) "\t"))))
- ;; Prepare the final format string for the table.
-
- (cond
- ;; Others.
- (lines (concat ".TS\n " table-format ";\n"
-
- (format "%s.\n"
- (let ((final-line ""))
-
- (when title-line
- (dotimes (i (length first-line))
- (setq final-line (concat final-line "cb" divider))))
-
- (setq final-line (concat final-line "\n"))
- (if alignment
- (setq final-line (concat final-line alignment))
- (dotimes (i (length first-line))
- (setq final-line (concat final-line "c" divider))))
- final-line))
-
- (format "%s.TE"
- (let ((final-line ""))
- (dolist (line-item lines)
- (cond
- (t
- (setq lines (org-split-string contents "\n"))
-
- (setq final-line (concat final-line
- (car (org-split-string line-item "\\\\")) "\n")))))
- final-line)))))))
-
-
-;;;; Table Cell
-
-(defun org-e-man-table-cell (table-cell contents info)
- "Transcode a TABLE-CELL element from Org to Man
-CONTENTS is the cell contents. INFO is a plist used as
-a communication channel."
- (concat (if (and contents
- org-e-man-table-scientific-notation
- (string-match orgtbl-exp-regexp contents))
- ;; Use appropriate format string for scientific
- ;; notation.
- (format org-e-man-table-scientific-notation
- (match-string 1 contents)
- (match-string 2 contents))
- contents)
- (when (org-export-get-next-element table-cell info) " \t ")))
-
-
-;;;; Table Row
-
-(defun org-e-man-table-row (table-row contents info)
- "Transcode a TABLE-ROW element from Org to Man
-CONTENTS is the contents of the row. INFO is a plist used as
-a communication channel."
- ;; Rules are ignored since table separators are deduced from
- ;; borders of the current row.
- (when (eq (org-element-property :type table-row) 'standard)
- (let* ((attr (mapconcat 'identity
- (org-element-property
- :attr_man (org-export-get-parent table-row))
- " "))
- ;; TABLE-ROW's borders are extracted from its first cell.
- (borders
- (org-export-table-cell-borders
- (car (org-element-contents table-row)) info)))
- (concat
- ;; Mark "hline" for horizontal lines.
- (cond ((and (memq 'top borders) (memq 'above borders)) "_\n"))
- contents "\\\\\n"
- (cond
- ;; When BOOKTABS are activated enforce bottom rule even when
- ;; no hline was specifically marked.
- ((and (memq 'bottom borders) (memq 'below borders)) "_\n")
- ((memq 'below borders) "_"))))))
-
-
-;;;; Target
-
-(defun org-e-man-target (target contents info)
- "Transcode a TARGET object from Org to Man.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format "\\fI%s\\fP"
- (org-export-solidify-link-text (org-element-property :value target))))
-
-
-;;;; Timestamp
-
-(defun org-e-man-timestamp (timestamp contents info)
- "Transcode a TIMESTAMP object from Org to Man.
- CONTENTS is nil. INFO is a plist holding contextual
- information."
- "")
-
-
-;;;; Underline
-
-(defun org-e-man-underline (underline contents info)
- "Transcode UNDERLINE from Org to Man.
-CONTENTS is the text with underline markup. INFO is a plist
-holding contextual information."
- (format "\\fI%s\\fP" contents))
-
-
-;;;; Verbatim
-
-(defun org-e-man-verbatim (verbatim contents info)
- "Transcode a VERBATIM object from Org to Man.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (format ".nf\n%s\n.fi" contents))
-
-
-;;;; Verse Block
-
-(defun org-e-man-verse-block (verse-block contents info)
- "Transcode a VERSE-BLOCK element from Org to Man.
-CONTENTS is verse block contents. INFO is a plist holding
-contextual information."
- (format ".RS\n.ft I\n%s\n.ft\n.RE" contents))
-
-
-
-;;; Interactive functions
-
-(defun org-e-man-export-to-man
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to a Man file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 the body
-without any markers.
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (let ((outfile (org-export-output-file-name ".man" subtreep pub-dir)))
- (org-export-to-file
- 'e-man outfile subtreep visible-only body-only ext-plist)))
-
-(defun org-e-man-export-to-pdf
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to Groff then process through to PDF.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write between
-markers.
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return PDF file's name."
- (interactive)
- (org-e-man-compile
- (org-e-man-export-to-man
- subtreep visible-only body-only ext-plist pub-dir)))
-
-(defun org-e-man-compile (grofffile)
- "Compile a Groff file.
-
-GROFFFILE is the name of the file being compiled. Processing is
-done through the command specified in `org-e-man-pdf-process'.
-
-Return PDF file name or an error if it couldn't be produced."
- (let* ((wconfig (current-window-configuration))
- (grofffile (file-truename grofffile))
- (base (file-name-sans-extension grofffile))
- errors)
- (message (format "Processing Groff file %s ..." grofffile))
- (unwind-protect
- (progn
- (cond
- ;; A function is provided: Apply it.
- ((functionp org-e-man-pdf-process)
- (funcall org-e-man-pdf-process (shell-quote-argument grofffile)))
- ;; A list is provided: Replace %b, %f and %o with appropriate
- ;; values in each command before applying it. Output is
- ;; redirected to "*Org PDF Groff Output*" buffer.
- ((consp org-e-man-pdf-process)
- (let* ((out-dir (or (file-name-directory grofffile) "./"))
- (outbuf (get-buffer-create "*Org PDF Groff Output*")))
- (mapc
- (lambda (command)
- (shell-command
- (replace-regexp-in-string
- "%b" (shell-quote-argument base)
- (replace-regexp-in-string
- "%f" (shell-quote-argument grofffile)
- (replace-regexp-in-string
- "%o" (shell-quote-argument out-dir) command t t) t t) t t)
- outbuf))
- org-e-man-pdf-process)
- ;; Collect standard errors from output buffer.
- (setq errors (org-e-man-collect-errors outbuf))))
- (t (error "No valid command to process to PDF")))
- (let ((pdffile (concat base ".pdf")))
- ;; Check for process failure. Provide collected errors if
- ;; possible.
- (if (not (file-exists-p pdffile))
- (error (concat (format "PDF file %s wasn't produced" pdffile)
- (when errors (concat ": " errors))))
- ;; Else remove log files, when specified, and signal end of
- ;; process to user, along with any error encountered.
- (when org-e-man-remove-logfiles
- (dolist (ext org-e-man-logfiles-extensions)
- (let ((file (concat base "." ext)))
- (when (file-exists-p file) (delete-file file)))))
- (message (concat "Process completed"
- (if (not errors) "."
- (concat " with errors: " errors)))))
- ;; Return output file name.
- pdffile))
- (set-window-configuration wconfig))))
-
-(defun org-e-man-collect-errors (buffer)
- "Collect some kind of errors from \"groff\" output
-BUFFER is the buffer containing output.
-Return collected error types as a string, or nil if there was
-none."
- (with-current-buffer buffer
- (save-excursion
- (goto-char (point-max))
- ;; Find final run
- nil)))
-
-
-(provide 'org-e-man)
-;;; org-e-man.el ends here
diff --git a/contrib/lisp/org-e-odt.el b/contrib/lisp/org-e-odt.el
deleted file mode 100644
index b2f7479..0000000
--- a/contrib/lisp/org-e-odt.el
+++ /dev/null
@@ -1,3762 +0,0 @@
-;;; org-e-odt.el --- OpenDocument Text exporter for Org-mode
-
-;; Copyright (C) 2010-2012 Free Software Foundation, Inc.
-
-;; Author: Jambunathan K <kjambunathan at gmail dot com>
-;; Keywords: outlines, hypermedia, calendar, wp
-;; Homepage: http://orgmode.org
-
-;; This file is not part of GNU Emacs.
-
-;; GNU Emacs 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.
-
-;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; Code:
-
-(eval-when-compile
- (require 'cl)
- (require 'table))
-(require 'format-spec)
-(require 'org-export)
-
-;;; Define Back-End
-
-(org-export-define-backend e-odt
- ((bold . org-e-odt-bold)
- (center-block . org-e-odt-center-block)
- (clock . org-e-odt-clock)
- (code . org-e-odt-code)
- (drawer . org-e-odt-drawer)
- (dynamic-block . org-e-odt-dynamic-block)
- (entity . org-e-odt-entity)
- (example-block . org-e-odt-example-block)
- (export-block . org-e-odt-export-block)
- (export-snippet . org-e-odt-export-snippet)
- (fixed-width . org-e-odt-fixed-width)
- (footnote-definition . org-e-odt-footnote-definition)
- (footnote-reference . org-e-odt-footnote-reference)
- (headline . org-e-odt-headline)
- (horizontal-rule . org-e-odt-horizontal-rule)
- (inline-src-block . org-e-odt-inline-src-block)
- (inlinetask . org-e-odt-inlinetask)
- (italic . org-e-odt-italic)
- (item . org-e-odt-item)
- (keyword . org-e-odt-keyword)
- (latex-environment . org-e-odt-latex-environment)
- (latex-fragment . org-e-odt-latex-fragment)
- (line-break . org-e-odt-line-break)
- (link . org-e-odt-link)
- (macro . org-e-odt-macro)
- (paragraph . org-e-odt-paragraph)
- (plain-list . org-e-odt-plain-list)
- (plain-text . org-e-odt-plain-text)
- (planning . org-e-odt-planning)
- (property-drawer . org-e-odt-property-drawer)
- (quote-block . org-e-odt-quote-block)
- (quote-section . org-e-odt-quote-section)
- (radio-target . org-e-odt-radio-target)
- (section . org-e-odt-section)
- (special-block . org-e-odt-special-block)
- (src-block . org-e-odt-src-block)
- (statistics-cookie . org-e-odt-statistics-cookie)
- (strike-through . org-e-odt-strike-through)
- (subscript . org-e-odt-subscript)
- (superscript . org-e-odt-superscript)
- (table . org-e-odt-table)
- (table-cell . org-e-odt-table-cell)
- (table-row . org-e-odt-table-row)
- (target . org-e-odt-target)
- (template . org-e-odt-template)
- (timestamp . org-e-odt-timestamp)
- (underline . org-e-odt-underline)
- (verbatim . org-e-odt-verbatim)
- (verse-block . org-e-odt-verse-block))
- :export-block "ODT"
- :options-alist
- ((:odt-styles-file "ODT_STYLES_FILE" nil nil t)
- (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments)))
-
-
-;;; Dependencies
-
-;;; Hooks
-
-;;; Function Declarations
-
-(declare-function org-id-find-id-file "org-id" (id))
-(declare-function hfy-face-to-style "htmlfontify" (fn))
-(declare-function hfy-face-or-def-to-name "htmlfontify" (fn))
-(declare-function archive-zip-extract "arc-mode.el" (archive name))
-(declare-function org-create-math-formula "org" (latex-frag &optional mathml-file))
-(declare-function browse-url-file-url "browse-url" (file))
-
-
-
-
-;;; Internal Variables
-
-(defconst org-e-odt-lib-dir
- (file-name-directory load-file-name)
- "Location of ODT exporter.
-Use this to infer values of `org-e-odt-styles-dir' and
-`org-e-odt-schema-dir'.")
-
-(defvar org-e-odt-data-dir
- (expand-file-name "../../etc/" org-e-odt-lib-dir)
- "Data directory for ODT exporter.
-Use this to infer values of `org-e-odt-styles-dir' and
-`org-e-odt-schema-dir'.")
-
-(defconst org-e-odt-special-string-regexps
- '(("\\\\-" . "&#x00ad;\\1") ; shy
- ("---\\([^-]\\)" . "&#x2014;\\1") ; mdash
- ("--\\([^-]\\)" . "&#x2013;\\1") ; ndash
- ("\\.\\.\\." . "&#x2026;")) ; hellip
- "Regular expressions for special string conversion.")
-
-(defconst org-e-odt-schema-dir-list
- (list
- (and org-e-odt-data-dir
- (expand-file-name "./schema/" org-e-odt-data-dir)) ; bail out
- (eval-when-compile
- (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
- (expand-file-name "./schema/" org-e-odt-data-dir))))
- "List of directories to search for OpenDocument schema files.
-Use this list to set the default value of
-`org-e-odt-schema-dir'. The entries in this list are
-populated heuristically based on the values of `org-e-odt-lib-dir'
-and `org-e-odt-data-dir'.")
-
-(defconst org-e-odt-styles-dir-list
- (list
- (and org-e-odt-data-dir
- (expand-file-name "./styles/" org-e-odt-data-dir)) ; bail out
- (eval-when-compile
- (and (boundp 'org-e-odt-data-dir) org-e-odt-data-dir ; see make install
- (expand-file-name "./styles/" org-e-odt-data-dir)))
- (expand-file-name "../../etc/styles/" org-e-odt-lib-dir) ; git
- (expand-file-name "./etc/styles/" org-e-odt-lib-dir) ; elpa
- (expand-file-name "./org/" data-directory) ; system
- )
- "List of directories to search for OpenDocument styles files.
-See `org-e-odt-styles-dir'. The entries in this list are populated
-heuristically based on the values of `org-e-odt-lib-dir' and
-`org-e-odt-data-dir'.")
-
-(defconst org-e-odt-styles-dir
- (let* ((styles-dir
- (catch 'styles-dir
- (message "Debug (org-e-odt): Searching for OpenDocument styles files...")
- (mapc (lambda (styles-dir)
- (when styles-dir
- (message "Debug (org-e-odt): Trying %s..." styles-dir)
- (when (and (file-readable-p
- (expand-file-name
- "OrgOdtContentTemplate.xml" styles-dir))
- (file-readable-p
- (expand-file-name
- "OrgOdtStyles.xml" styles-dir)))
- (message "Debug (org-e-odt): Using styles under %s"
- styles-dir)
- (throw 'styles-dir styles-dir))))
- org-e-odt-styles-dir-list)
- nil)))
- (unless styles-dir
- (error "Error (org-e-odt): Cannot find factory styles files, aborting"))
- styles-dir)
- "Directory that holds auxiliary XML files used by the ODT exporter.
-
-This directory contains the following XML files -
- \"OrgOdtStyles.xml\" and \"OrgOdtContentTemplate.xml\". These
- XML files are used as the default values of
- `org-e-odt-styles-file' and
- `org-e-odt-content-template-file'.
-
-The default value of this variable varies depending on the
-version of org in use and is initialized from
-`org-e-odt-styles-dir-list'. Note that the user could be using org
-from one of: org's own private git repository, GNU ELPA tar or
-standard Emacs.")
-
-(defconst org-e-odt-bookmark-prefix "OrgXref.")
-
-(defconst org-e-odt-manifest-file-entry-tag
- "\n<manifest:file-entry manifest:media-type=\"%s\" manifest:full-path=\"%s\"%s/>")
-
-(defconst org-e-odt-file-extensions
- '(("odt" . "OpenDocument Text")
- ("ott" . "OpenDocument Text Template")
- ("odm" . "OpenDocument Master Document")
- ("ods" . "OpenDocument Spreadsheet")
- ("ots" . "OpenDocument Spreadsheet Template")
- ("odg" . "OpenDocument Drawing (Graphics)")
- ("otg" . "OpenDocument Drawing Template")
- ("odp" . "OpenDocument Presentation")
- ("otp" . "OpenDocument Presentation Template")
- ("odi" . "OpenDocument Image")
- ("odf" . "OpenDocument Formula")
- ("odc" . "OpenDocument Chart")))
-
-(defvar org-e-odt-table-style-format
- "
-<style:style style:name=\"%s\" style:family=\"table\">
- <style:table-properties style:rel-width=\"%d%%\" fo:margin-top=\"0cm\" fo:margin-bottom=\"0.20cm\" table:align=\"center\"/>
-</style:style>
-"
- "Template for auto-generated Table styles.")
-
-(defvar org-e-odt-automatic-styles '()
- "Registry of automatic styles for various OBJECT-TYPEs.
-The variable has the following form:
-\(\(OBJECT-TYPE-A
- \(\(OBJECT-NAME-A.1 OBJECT-PROPS-A.1\)
- \(OBJECT-NAME-A.2 OBJECT-PROPS-A.2\) ...\)\)
- \(OBJECT-TYPE-B
- \(\(OBJECT-NAME-B.1 OBJECT-PROPS-B.1\)
- \(OBJECT-NAME-B.2 OBJECT-PROPS-B.2\) ...\)\)
- ...\).
-
-OBJECT-TYPEs could be \"Section\", \"Table\", \"Figure\" etc.
-OBJECT-PROPS is (typically) a plist created by passing
-\"#+ATTR_ODT: \" option to `org-e-odt-parse-block-attributes'.
-
-Use `org-e-odt-add-automatic-style' to add update this variable.'")
-
-(defvar org-e-odt-object-counters nil
- "Running counters for various OBJECT-TYPEs.
-Use this to generate automatic names and style-names. See
-`org-e-odt-add-automatic-style'.")
-
-(defvar org-e-odt-src-block-paragraph-format
- "<style:style style:name=\"OrgSrcBlock\" style:family=\"paragraph\" style:parent-style-name=\"Preformatted_20_Text\">
- <style:paragraph-properties fo:background-color=\"%s\" fo:padding=\"0.049cm\" fo:border=\"0.51pt solid #000000\" style:shadow=\"none\">
- <style:background-image/>
- </style:paragraph-properties>
- <style:text-properties fo:color=\"%s\"/>
- </style:style>"
- "Custom paragraph style for colorized source and example blocks.
-This style is much the same as that of \"OrgFixedWidthBlock\"
-except that the foreground and background colors are set
-according to the default face identified by the `htmlfontify'.")
-
-(defvar hfy-optimisations)
-(defvar org-e-odt-embedded-formulas-count 0)
-(defvar org-e-odt-entity-frame-styles
- '(("As-CharImage" "__Figure__" ("OrgInlineImage" nil "as-char"))
- ("ParagraphImage" "__Figure__" ("OrgDisplayImage" nil "paragraph"))
- ("PageImage" "__Figure__" ("OrgPageImage" nil "page"))
- ("CaptionedAs-CharImage" "__Figure__"
- ("OrgCaptionedImage"
- " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
- ("OrgInlineImage" nil "as-char"))
- ("CaptionedParagraphImage" "__Figure__"
- ("OrgCaptionedImage"
- " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
- ("OrgImageCaptionFrame" nil "paragraph"))
- ("CaptionedPageImage" "__Figure__"
- ("OrgCaptionedImage"
- " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph")
- ("OrgPageImageCaptionFrame" nil "page"))
- ("InlineFormula" "__MathFormula__" ("OrgInlineFormula" nil "as-char"))
- ("DisplayFormula" "__MathFormula__" ("OrgDisplayFormula" nil "as-char"))
- ("CaptionedDisplayFormula" "__MathFormula__"
- ("OrgCaptionedFormula" nil "paragraph")
- ("OrgFormulaCaptionFrame" nil "as-char"))))
-
-(defvar org-e-odt-embedded-images-count 0)
-(defvar org-e-odt-image-size-probe-method
- (append (and (executable-find "identify") '(imagemagick)) ; See Bug#10675
- '(emacs fixed))
- "Ordered list of methods for determining image sizes.")
-
-(defvar org-e-odt-default-image-sizes-alist
- '(("as-char" . (5 . 0.4))
- ("paragraph" . (5 . 5)))
- "Hardcoded image dimensions one for each of the anchor
- methods.")
-
-;; A4 page size is 21.0 by 29.7 cms
-;; The default page settings has 2cm margin on each of the sides. So
-;; the effective text area is 17.0 by 25.7 cm
-(defvar org-e-odt-max-image-size '(17.0 . 20.0)
- "Limiting dimensions for an embedded image.")
-
-(defvar org-e-odt-label-styles
- '(("math-formula" "%c" "text" "(%n)")
- ("math-label" "(%n)" "text" "(%n)")
- ("category-and-value" "%e %n: %c" "category-and-value" "%e %n")
- ("value" "%e %n: %c" "value" "%n"))
- "Specify how labels are applied and referenced.
-This is an alist where each element is of the
-form (LABEL-STYLE-NAME LABEL-ATTACH-FMT LABEL-REF-MODE
-LABEL-REF-FMT).
-
-LABEL-ATTACH-FMT controls how labels and captions are attached to
-an entity. It may contain following specifiers - %e, %n and %c.
-%e is replaced with the CATEGORY-NAME. %n is replaced with
-\"<text:sequence ...> SEQNO </text:sequence>\". %c is replaced
-with CAPTION. See `org-e-odt-format-label-definition'.
-
-LABEL-REF-MODE and LABEL-REF-FMT controls how label references
-are generated. The following XML is generated for a label
-reference - \"<text:sequence-ref
-text:reference-format=\"LABEL-REF-MODE\" ...> LABEL-REF-FMT
-</text:sequence-ref>\". LABEL-REF-FMT may contain following
-specifiers - %e and %n. %e is replaced with the CATEGORY-NAME.
-%n is replaced with SEQNO. See
-`org-e-odt-format-label-reference'.")
-
-(defvar org-e-odt-category-map-alist
- '(("__Table__" "Table" "value" "Table")
- ("__Figure__" "Illustration" "value" "Figure")
- ("__MathFormula__" "Text" "math-formula" "Equation")
- ("__DvipngImage__" "Equation" "value" "Equation")
- ("__Listing__" "Listing" "value" "Listing")
- ;; ("__Table__" "Table" "category-and-value")
- ;; ("__Figure__" "Figure" "category-and-value")
- ;; ("__DvipngImage__" "Equation" "category-and-value")
- )
- "Map a CATEGORY-HANDLE to OD-VARIABLE and LABEL-STYLE.
-This is a list where each entry is of the form \\(CATEGORY-HANDLE
-OD-VARIABLE LABEL-STYLE CATEGORY-NAME\\). CATEGORY_HANDLE
-identifies the captionable entity in question. OD-VARIABLE is
-the OpenDocument sequence counter associated with the entity.
-These counters are declared within
-\"<text:sequence-decls>...</text:sequence-decls>\" block of
-`org-e-odt-content-template-file'. LABEL-STYLE is a key into
-`org-e-odt-label-styles' and specifies how a given entity should
-be captioned and referenced. CATEGORY-NAME is used for
-qualifying captions on export. You can modify the CATEGORY-NAME
-used in the exported document by modifying
-`org-export-dictionary'. For example, an embedded image in an
-English document is captioned as \"Figure 1: Orgmode Logo\", by
-default. If you want the image to be captioned as \"Illustration
-1: Orgmode Logo\" instead, install an entry in
-`org-export-dictionary' which translates \"Figure\" to
-\"Illustration\" when the language is \"en\" and encoding is
-`:utf-8'.")
-
-(defvar org-e-odt-manifest-file-entries nil)
-(defvar hfy-user-sheet-assoc)
-
-(defvar org-e-odt-zip-dir nil
- "Temporary work directory for OpenDocument exporter.")
-
-
-
-;;; User Configuration Variables
-
-(defgroup org-export-e-odt nil
- "Options for exporting Org mode files to ODT."
- :tag "Org Export ODT"
- :group 'org-export)
-
-
-;;;; Debugging
-
-(defcustom org-e-odt-prettify-xml nil
- "Specify whether or not the xml output should be prettified.
-When this option is turned on, `indent-region' is run on all
-component xml buffers before they are saved. Turn this off for
-regular use. Turn this on if you need to examine the xml
-visually."
- :group 'org-export-e-odt
- :version "24.1"
- :type 'boolean)
-
-
-;;;; Document schema
-
-(defcustom org-e-odt-schema-dir
- (let* ((schema-dir
- (catch 'schema-dir
- (message "Debug (org-e-odt): Searching for OpenDocument schema files...")
- (mapc
- (lambda (schema-dir)
- (when schema-dir
- (message "Debug (org-e-odt): Trying %s..." schema-dir)
- (when (and (file-readable-p
- (expand-file-name "od-manifest-schema-v1.2-cs01.rnc"
- schema-dir))
- (file-readable-p
- (expand-file-name "od-schema-v1.2-cs01.rnc"
- schema-dir))
- (file-readable-p
- (expand-file-name "schemas.xml" schema-dir)))
- (message "Debug (org-e-odt): Using schema files under %s"
- schema-dir)
- (throw 'schema-dir schema-dir))))
- org-e-odt-schema-dir-list)
- (message "Debug (org-e-odt): No OpenDocument schema files installed")
- nil)))
- schema-dir)
- "Directory that contains OpenDocument schema files.
-
-This directory contains:
-1. rnc files for OpenDocument schema
-2. a \"schemas.xml\" file that specifies locating rules needed
- for auto validation of OpenDocument XML files.
-
-Use the customize interface to set this variable. This ensures
-that `rng-schema-locating-files' is updated and auto-validation
-of OpenDocument XML takes place based on the value
-`rng-nxml-auto-validate-flag'.
-
-The default value of this variable varies depending on the
-version of org in use and is initialized from
-`org-e-odt-schema-dir-list'. The OASIS schema files are available
-only in the org's private git repository. It is *not* bundled
-with GNU ELPA tar or standard Emacs distribution."
- :type '(choice
- (const :tag "Not set" nil)
- (directory :tag "Schema directory"))
- :group 'org-export-e-odt
- :version "24.1"
- :set
- (lambda (var value)
- "Set `org-e-odt-schema-dir'.
-Also add it to `rng-schema-locating-files'."
- (let ((schema-dir value))
- (set var
- (if (and
- (file-readable-p
- (expand-file-name "od-manifest-schema-v1.2-cs01.rnc" schema-dir))
- (file-readable-p
- (expand-file-name "od-schema-v1.2-cs01.rnc" schema-dir))
- (file-readable-p
- (expand-file-name "schemas.xml" schema-dir)))
- schema-dir
- (when value
- (message "Error (org-e-odt): %s has no OpenDocument schema files"
- value))
- nil)))
- (when org-e-odt-schema-dir
- (eval-after-load 'rng-loc
- '(add-to-list 'rng-schema-locating-files
- (expand-file-name "schemas.xml"
- org-e-odt-schema-dir))))))
-
-
-;;;; Document styles
-
-(defcustom org-e-odt-content-template-file nil
- "Template file for \"content.xml\".
-The exporter embeds the exported content just before
-\"</office:text>\" element.
-
-If unspecified, the file named \"OrgOdtContentTemplate.xml\"
-under `org-e-odt-styles-dir' is used."
- :type 'file
- :group 'org-export-e-odt
- :version "24.1")
-
-(defcustom org-e-odt-styles-file nil
- "Default styles file for use with ODT export.
-Valid values are one of:
-1. nil
-2. path to a styles.xml file
-3. path to a *.odt or a *.ott file
-4. list of the form (ODT-OR-OTT-FILE (FILE-MEMBER-1 FILE-MEMBER-2
-...))
-
-In case of option 1, an in-built styles.xml is used. See
-`org-e-odt-styles-dir' for more information.
-
-In case of option 3, the specified file is unzipped and the
-styles.xml embedded therein is used.
-
-In case of option 4, the specified ODT-OR-OTT-FILE is unzipped
-and FILE-MEMBER-1, FILE-MEMBER-2 etc are copied in to the
-generated odt file. Use relative path for specifying the
-FILE-MEMBERS. styles.xml must be specified as one of the
-FILE-MEMBERS.
-
-Use options 1, 2 or 3 only if styles.xml alone suffices for
-achieving the desired formatting. Use option 4, if the styles.xml
-references additional files like header and footer images for
-achieving the desired formatting.
-
-Use \"#+ODT_STYLES_FILE: ...\" directive to set this variable on
-a per-file basis. For example,
-
-#+ODT_STYLES_FILE: \"/path/to/styles.xml\" or
-#+ODT_STYLES_FILE: (\"/path/to/file.ott\" (\"styles.xml\" \"image/hdr.png\"))."
- :group 'org-export-e-odt
- :version "24.1"
- :type
- '(choice
- (const :tag "Factory settings" nil)
- (file :must-match t :tag "styles.xml")
- (file :must-match t :tag "ODT or OTT file")
- (list :tag "ODT or OTT file + Members"
- (file :must-match t :tag "ODF Text or Text Template file")
- (cons :tag "Members"
- (file :tag " Member" "styles.xml")
- (repeat (file :tag "Member"))))))
-
-(defcustom org-e-odt-display-outline-level 2
- "Outline levels considered for enumerating captioned entities."
- :group 'org-export-e-odt
- :version "24.2"
- :type 'integer)
-
-;;;; Document conversion
-
-(defcustom org-e-odt-convert-processes
- '(("LibreOffice"
- "soffice --headless --convert-to %f%x --outdir %d %i")
- ("unoconv"
- "unoconv -f %f -o %d %i"))
- "Specify a list of document converters and their usage.
-The converters in this list are offered as choices while
-customizing `org-e-odt-convert-process'.
-
-This variable is a list where each element is of the
-form (CONVERTER-NAME CONVERTER-CMD). CONVERTER-NAME is the name
-of the converter. CONVERTER-CMD is the shell command for the
-converter and can contain format specifiers. These format
-specifiers are interpreted as below:
-
-%i input file name in full
-%I input file name as a URL
-%f format of the output file
-%o output file name in full
-%O output file name as a URL
-%d output dir in full
-%D output dir as a URL.
-%x extra options as set in `org-e-odt-convert-capabilities'."
- :group 'org-export-e-odt
- :version "24.1"
- :type
- '(choice
- (const :tag "None" nil)
- (alist :tag "Converters"
- :key-type (string :tag "Converter Name")
- :value-type (group (string :tag "Command line")))))
-
-(defcustom org-e-odt-convert-process "LibreOffice"
- "Use this converter to convert from \"odt\" format to other formats.
-During customization, the list of converter names are populated
-from `org-e-odt-convert-processes'."
- :group 'org-export-e-odt
- :version "24.1"
- :type '(choice :convert-widget
- (lambda (w)
- (apply 'widget-convert (widget-type w)
- (eval (car (widget-get w :args)))))
- `((const :tag "None" nil)
- ,@(mapcar (lambda (c)
- `(const :tag ,(car c) ,(car c)))
- org-e-odt-convert-processes))))
-
-(defcustom org-e-odt-convert-capabilities
- '(("Text"
- ("odt" "ott" "doc" "rtf" "docx")
- (("pdf" "pdf") ("odt" "odt") ("rtf" "rtf") ("ott" "ott")
- ("doc" "doc" ":\"MS Word 97\"") ("docx" "docx") ("html" "html")))
- ("Web"
- ("html")
- (("pdf" "pdf") ("odt" "odt") ("html" "html")))
- ("Spreadsheet"
- ("ods" "ots" "xls" "csv" "xlsx")
- (("pdf" "pdf") ("ots" "ots") ("html" "html") ("csv" "csv") ("ods" "ods")
- ("xls" "xls") ("xlsx" "xlsx")))
- ("Presentation"
- ("odp" "otp" "ppt" "pptx")
- (("pdf" "pdf") ("swf" "swf") ("odp" "odp") ("otp" "otp") ("ppt" "ppt")
- ("pptx" "pptx") ("odg" "odg"))))
- "Specify input and output formats of `org-e-odt-convert-process'.
-More correctly, specify the set of input and output formats that
-the user is actually interested in.
-
-This variable is an alist where each element is of the
-form (DOCUMENT-CLASS INPUT-FMT-LIST OUTPUT-FMT-ALIST).
-INPUT-FMT-LIST is a list of INPUT-FMTs. OUTPUT-FMT-ALIST is an
-alist where each element is of the form (OUTPUT-FMT
-OUTPUT-FILE-EXTENSION EXTRA-OPTIONS).
-
-The variable is interpreted as follows:
-`org-e-odt-convert-process' can take any document that is in
-INPUT-FMT-LIST and produce any document that is in the
-OUTPUT-FMT-LIST. A document converted to OUTPUT-FMT will have
-OUTPUT-FILE-EXTENSION as the file name extension. OUTPUT-FMT
-serves dual purposes:
-- It is used for populating completion candidates during
- `org-e-odt-convert' commands.
-- It is used as the value of \"%f\" specifier in
- `org-e-odt-convert-process'.
-
-EXTRA-OPTIONS is used as the value of \"%x\" specifier in
-`org-e-odt-convert-process'.
-
-DOCUMENT-CLASS is used to group a set of file formats in
-INPUT-FMT-LIST in to a single class.
-
-Note that this variable inherently captures how LibreOffice based
-converters work. LibreOffice maps documents of various formats
-to classes like Text, Web, Spreadsheet, Presentation etc and
-allow document of a given class (irrespective of it's source
-format) to be converted to any of the export formats associated
-with that class.
-
-See default setting of this variable for an typical
-configuration."
- :group 'org-export-e-odt
- :version "24.1"
- :type
- '(choice
- (const :tag "None" nil)
- (alist :tag "Capabilities"
- :key-type (string :tag "Document Class")
- :value-type
- (group (repeat :tag "Input formats" (string :tag "Input format"))
- (alist :tag "Output formats"
- :key-type (string :tag "Output format")
- :value-type
- (group (string :tag "Output file extension")
- (choice
- (const :tag "None" nil)
- (string :tag "Extra options"))))))))
-
-(defcustom org-e-odt-preferred-output-format nil
- "Automatically post-process to this format after exporting to \"odt\".
-Interactive commands `org-export-as-e-odt' and
-`org-export-as-e-odt-and-open' export first to \"odt\" format and
-then use `org-e-odt-convert-process' to convert the
-resulting document to this format. During customization of this
-variable, the list of valid values are populated based on
-`org-e-odt-convert-capabilities'."
- :group 'org-export-e-odt
- :version "24.1"
- :type '(choice :convert-widget
- (lambda (w)
- (apply 'widget-convert (widget-type w)
- (eval (car (widget-get w :args)))))
- `((const :tag "None" nil)
- ,@(mapcar (lambda (c)
- `(const :tag ,c ,c))
- (org-e-odt-reachable-formats "odt")))))
-
-
-;;;; Drawers
-
-(defcustom org-e-odt-format-drawer-function nil
- "Function called to format a drawer in HTML code.
-
-The function must accept two parameters:
- NAME the drawer name, like \"LOGBOOK\"
- CONTENTS the contents of the drawer.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-odt-format-drawer-default \(name contents\)
- \"Format a drawer element for HTML export.\"
- contents\)"
- :group 'org-export-e-odt
- :type 'function)
-
-
-;;;; Headline
-
-(defcustom org-e-odt-format-headline-function nil
- "Function to format headline text.
-
-This function will be called with 5 arguments:
-TODO the todo keyword \(string or nil\).
-TODO-TYPE the type of todo \(symbol: `todo', `done', nil\)
-PRIORITY the priority of the headline \(integer or nil\)
-TEXT the main headline text \(string\).
-TAGS the tags string, separated with colons \(string or nil\).
-
-The function result will be used in the section format string.
-
-As an example, one could set the variable to the following, in
-order to reproduce the default set-up:
-
-\(defun org-e-odt-format-headline \(todo todo-type priority text tags\)
- \"Default format function for an headline.\"
- \(concat \(when todo
- \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo\)\)
- \(when priority
- \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
- text
- \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)"
- :group 'org-export-e-odt
- :type 'function)
-
-
-;;;; Inlinetasks
-
-(defcustom org-e-odt-format-inlinetask-function nil
- "Function called to format an inlinetask in HTML code.
-
-The function must accept six parameters:
- TODO the todo keyword, as a string
- TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
- PRIORITY the inlinetask priority, as a string
- NAME the inlinetask name, as a string.
- TAGS the inlinetask tags, as a string.
- CONTENTS the contents of the inlinetask, as a string.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-odt-format-inlinetask \(todo type priority name tags contents\)
-\"Format an inline task element for HTML export.\"
- \(let \(\(full-title
- \(concat
- \(when todo
- \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo\)\)
- \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
- title
- \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)\)
- \(format \(concat \"\\\\begin{center}\\n\"
- \"\\\\fbox{\\n\"
- \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
- \"%s\\n\\n\"
- \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
- \"%s\"
- \"\\\\end{minipage}}\"
- \"\\\\end{center}\"\)
- full-title contents\)\)"
- :group 'org-export-e-odt
- :type 'function)
-
-
-;;;; Links
-
-(defcustom org-e-odt-inline-image-rules
- '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\)\\'"))
- "Rules characterizing image files that can be inlined into HTML.
-
-A rule consists in an association whose key is the type of link
-to consider, and value is a regexp that will be matched against
-link's path.
-
-Note that, by default, the image extension *actually* allowed
-depend on the way the HTML file is processed. When used with
-pdflatex, pdf, jpg and png images are OK. When processing
-through dvi to Postscript, only ps and eps are allowed. The
-default we use here encompasses both."
- :group 'org-export-e-odt
- :type '(alist :key-type (string :tag "Type")
- :value-type (regexp :tag "Path")))
-
-(defcustom org-e-odt-pixels-per-inch display-pixels-per-inch
- "Scaling factor for converting images pixels to inches.
-Use this for sizing of embedded images. See Info node `(org)
-Images in ODT export' for more information."
- :type 'float
- :group 'org-export-e-odt
- :version "24.1")
-
-
-;;;; Plain text
-
-(defcustom org-e-odt-quotes
- '(("fr"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "« ")
- ("\\(\\S-\\)\"" . "» ")
- ("\\(\\s-\\|(\\|^\\)'" . "'"))
- ("en"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "“")
- ("\\(\\S-\\)\"" . "”")
- ("\\(\\s-\\|(\\|^\\)'" . "‘")
- ("\\(\\S-\\)'" . "’")))
- "Alist for quotes to use when converting english double-quotes.
-
-The CAR of each item in this alist is the language code.
-The CDR of each item in this alist is a list of three CONS:
-- the first CONS defines the opening quote;
-- the second CONS defines the closing quote;
-- the last CONS defines single quotes.
-
-For each item in a CONS, the first string is a regexp
-for allowed characters before/after the quote, the second
-string defines the replacement string for this quote."
- :group 'org-export-e-odt
- :type '(list
- (cons :tag "Opening quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))
- (cons :tag "Closing quote"
- (string :tag "Regexp for char after ")
- (string :tag "Replacement quote "))
- (cons :tag "Single quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))))
-
-
-;;;; Src Block
-
-(defcustom org-e-odt-create-custom-styles-for-srcblocks t
- "Whether custom styles for colorized source blocks be automatically created.
-When this option is turned on, the exporter creates custom styles
-for source blocks based on the advice of `htmlfontify'. Creation
-of custom styles happen as part of `org-e-odt-hfy-face-to-css'.
-
-When this option is turned off exporter does not create such
-styles.
-
-Use the latter option if you do not want the custom styles to be
-based on your current display settings. It is necessary that the
-styles.xml already contains needed styles for colorizing to work.
-
-This variable is effective only if
-`org-e-odt-fontify-srcblocks' is turned on."
- :group 'org-export-e-odt
- :version "24.1"
- :type 'boolean)
-
-(defcustom org-e-odt-fontify-srcblocks t
- "Specify whether or not source blocks need to be fontified.
-Turn this option on if you want to colorize the source code
-blocks in the exported file. For colorization to work, you need
-to make available an enhanced version of `htmlfontify' library."
- :type 'boolean
- :group 'org-export-e-odt
- :version "24.1")
-
-
-;;;; Table
-
-(defcustom org-e-odt-table-caption-above t
- "When non-nil, place caption string at the beginning of the table.
-Otherwise, place it near the end."
- :group 'org-export-e-odt
- :type 'boolean)
-
-(defcustom org-e-odt-table-styles
- '(("OrgEquation" "OrgEquation"
- ((use-first-column-styles . t)
- (use-last-column-styles . t))))
- "Specify how Table Styles should be derived from a Table Template.
-This is a list where each element is of the
-form (TABLE-STYLE-NAME TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS).
-
-TABLE-STYLE-NAME is the style associated with the table through
-\"#+ATTR_ODT: :style TABLE-STYLE-NAME\" line.
-
-TABLE-TEMPLATE-NAME is a set of - upto 9 - automatic
-TABLE-CELL-STYLE-NAMEs and PARAGRAPH-STYLE-NAMEs (as defined
-below) that is included in
-`org-e-odt-content-template-file'.
-
-TABLE-CELL-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
- \"TableCell\"
-PARAGRAPH-STYLE-NAME := TABLE-TEMPLATE-NAME + TABLE-CELL-TYPE +
- \"TableParagraph\"
-TABLE-CELL-TYPE := \"FirstRow\" | \"LastColumn\" |
- \"FirstRow\" | \"LastRow\" |
- \"EvenRow\" | \"OddRow\" |
- \"EvenColumn\" | \"OddColumn\" | \"\"
-where \"+\" above denotes string concatenation.
-
-TABLE-CELL-OPTIONS is an alist where each element is of the
-form (TABLE-CELL-STYLE-SELECTOR . ON-OR-OFF).
-TABLE-CELL-STYLE-SELECTOR := `use-first-row-styles' |
- `use-last-row-styles' |
- `use-first-column-styles' |
- `use-last-column-styles' |
- `use-banding-rows-styles' |
- `use-banding-columns-styles' |
- `use-first-row-styles'
-ON-OR-OFF := `t' | `nil'
-
-For example, with the following configuration
-
-\(setq org-e-odt-table-styles
- '\(\(\"TableWithHeaderRowsAndColumns\" \"Custom\"
- \(\(use-first-row-styles . t\)
- \(use-first-column-styles . t\)\)\)
- \(\"TableWithHeaderColumns\" \"Custom\"
- \(\(use-first-column-styles . t\)\)\)\)\)
-
-1. A table associated with \"TableWithHeaderRowsAndColumns\"
- style will use the following table-cell styles -
- \"CustomFirstRowTableCell\", \"CustomFirstColumnTableCell\",
- \"CustomTableCell\" and the following paragraph styles
- \"CustomFirstRowTableParagraph\",
- \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
- as appropriate.
-
-2. A table associated with \"TableWithHeaderColumns\" style will
- use the following table-cell styles -
- \"CustomFirstColumnTableCell\", \"CustomTableCell\" and the
- following paragraph styles
- \"CustomFirstColumnTableParagraph\", \"CustomTableParagraph\"
- as appropriate..
-
-Note that TABLE-TEMPLATE-NAME corresponds to the
-\"<table:table-template>\" elements contained within
-\"<office:styles>\". The entries (TABLE-STYLE-NAME
-TABLE-TEMPLATE-NAME TABLE-CELL-OPTIONS) correspond to
-\"table:template-name\" and \"table:use-first-row-styles\" etc
-attributes of \"<table:table>\" element. Refer ODF-1.2
-specification for more information. Also consult the
-implementation filed under `org-e-odt-get-table-cell-styles'.
-
-The TABLE-STYLE-NAME \"OrgEquation\" is used internally for
-formatting of numbered display equations. Do not delete this
-style from the list."
- :group 'org-export-e-odt
- :version "24.1"
- :type '(choice
- (const :tag "None" nil)
- (repeat :tag "Table Styles"
- (list :tag "Table Style Specification"
- (string :tag "Table Style Name")
- (string :tag "Table Template Name")
- (alist :options (use-first-row-styles
- use-last-row-styles
- use-first-column-styles
- use-last-column-styles
- use-banding-rows-styles
- use-banding-columns-styles)
- :key-type symbol
- :value-type (const :tag "True" t))))))
-
-
-
-;;; Internal functions
-
-;;;; Date
-
-(defun org-e-odt--date (&optional org-ts fmt)
- (save-match-data
- (let* ((time
- (and (stringp org-ts)
- (string-match org-ts-regexp0 org-ts)
- (apply 'encode-time
- (org-fix-decoded-time
- (org-parse-time-string (match-string 0 org-ts) t)))))
- date)
- (cond
- (fmt (format-time-string fmt time))
- (t (setq date (format-time-string "%Y-%m-%dT%H:%M:%S%z" time))
- (format "%s:%s" (substring date 0 -2) (substring date -2)))))))
-
-;;;; Frame
-
-(defun org-e-odt--frame (text width height style &optional extra
- anchor-type)
- (let ((frame-attrs
- (concat
- (if width (format " svg:width=\"%0.2fcm\"" width) "")
- (if height (format " svg:height=\"%0.2fcm\"" height) "")
- extra
- (format " text:anchor-type=\"%s\"" (or anchor-type "paragraph")))))
- (format
- "\n<draw:frame draw:style-name=\"%s\"%s>\n%s\n</draw:frame>"
- style frame-attrs
- (concat text
- (let ((title (get-text-property 0 :title text))
- (desc (get-text-property 0 :description text)))
- (concat (and title
- (format "<svg:title>%s</svg:title>"
- (org-e-odt-encode-plain-text title t)))
- (and desc
- (format "<svg:desc>%s</svg:desc>"
- (org-e-odt-encode-plain-text desc t)))))))))
-
-;;;; Library wrappers
-
-(defun org-e-odt--adopt-elements (parent &rest children)
- (prog1 parent
- (mapc (lambda (child)
- (let ((parent-1 (org-element-adopt-element parent child nil)))
- (assert (eq parent-1 parent))))
- children)))
-
-(defun org-e-odt--zip-extract (archive members target)
- (when (atom members) (setq members (list members)))
- (mapc (lambda (archive member target)
- (require 'arc-mode)
- (let* ((--quote-file-name
- ;; This is shamelessly stolen from `archive-zip-extract'.
- (lambda (name)
- (if (or (not (memq system-type '(windows-nt ms-dos)))
- (and (boundp 'w32-quote-process-args)
- (null w32-quote-process-args)))
- (shell-quote-argument name)
- name)))
- (target (funcall --quote-file-name target))
- (archive (expand-file-name archive))
- (archive-zip-extract
- (list "unzip" "-qq" "-o" "-d" target))
- exit-code command-output)
- (setq command-output
- (with-temp-buffer
- (setq exit-code (archive-zip-extract archive member))
- (buffer-string)))
- (unless (zerop exit-code)
- (message command-output)
- (error "Extraction failed"))))
- members))
-
-;;;; Textbox
-
-(defun org-e-odt--textbox (text width height style &optional
- extra anchor-type)
- (org-e-odt--frame
- (format "\n<draw:text-box %s>%s\n</draw:text-box>"
- (concat (format " fo:min-height=\"%0.2fcm\"" (or height .2))
- (and (not width)
- (format " fo:min-width=\"%0.2fcm\"" (or width .2))))
- text)
- width nil style extra anchor-type))
-
-
-
-;;;; Table of Contents
-
-(defun org-e-odt-begin-toc (index-title depth)
- (concat
- (format "
- <text:table-of-content text:style-name=\"Sect2\" text:protected=\"true\" text:name=\"Table of Contents1\">
- <text:table-of-content-source text:outline-level=\"%d\">
- <text:index-title-template text:style-name=\"Contents_20_Heading\">%s</text:index-title-template>
-" depth index-title)
-
- (let ((levels (number-sequence 1 10)))
- (mapconcat
- (lambda (level)
- (format
- "
- <text:table-of-content-entry-template text:outline-level=\"%d\" text:style-name=\"Contents_20_%d\">
- <text:index-entry-link-start text:style-name=\"Internet_20_link\"/>
- <text:index-entry-chapter/>
- <text:index-entry-text/>
- <text:index-entry-link-end/>
- </text:table-of-content-entry-template>
-" level level)) levels ""))
-
- (format "
- </text:table-of-content-source>
-
- <text:index-body>
- <text:index-title text:style-name=\"Sect1\" text:name=\"Table of Contents1_Head\">
- <text:p text:style-name=\"Contents_20_Heading\">%s</text:p>
- </text:index-title>
- " index-title)))
-
-(defun org-e-odt-end-toc ()
- (format "
- </text:index-body>
- </text:table-of-content>
-"))
-
-
-
-(defun* org-e-odt-format-toc-headline
- (todo todo-type priority text tags
- &key level section-number headline-label &allow-other-keys)
- (setq text (concat
- (and org-export-with-section-numbers
- (concat section-number ". "))
- text
- (and tags
- (concat
- "<text:tab/>"
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTag" tags)))))
- (when todo
- (setq text (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTodo" text)))
- (org-e-odt-format-link text (concat "#" headline-label) t))
-
-(defun org-e-odt-toc (depth info)
- (assert (wholenump depth))
- (let* ((title (org-export-translate "Table of Contents" :utf-8 info))
- (headlines (org-export-collect-headlines info depth)))
-
- (when headlines
- (concat
- (org-e-odt-begin-toc title depth)
-
- (mapconcat
- (lambda (headline)
- (let* ((entry (org-e-odt-format-headline--wrap
- headline info 'org-e-odt-format-toc-headline))
- (level (org-export-get-relative-level headline info))
- (style (format "Contents_20_%d" level)))
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- style entry)))
- headlines "\n")
-
- (org-e-odt-end-toc)))))
-
-
-;;;; Document styles
-
-(defun org-e-odt-add-automatic-style (object-type &optional object-props)
- "Create an automatic style of type OBJECT-TYPE with param OBJECT-PROPS.
-OBJECT-PROPS is (typically) a plist created by passing
-\"#+ATTR_ODT: \" option of the object in question to
-`org-e-odt-parse-block-attributes'.
-
-Use `org-e-odt-object-counters' to generate an automatic
-OBJECT-NAME and STYLE-NAME. If OBJECT-PROPS is non-nil, add a
-new entry in `org-e-odt-automatic-styles'. Return (OBJECT-NAME
-. STYLE-NAME)."
- (assert (stringp object-type))
- (let* ((object (intern object-type))
- (seqvar object)
- (seqno (1+ (or (plist-get org-e-odt-object-counters seqvar) 0)))
- (object-name (format "%s%d" object-type seqno)) style-name)
- (setq org-e-odt-object-counters
- (plist-put org-e-odt-object-counters seqvar seqno))
- (when object-props
- (setq style-name (format "Org%s" object-name))
- (setq org-e-odt-automatic-styles
- (plist-put org-e-odt-automatic-styles object
- (append (list (list style-name object-props))
- (plist-get org-e-odt-automatic-styles object)))))
- (cons object-name style-name)))
-
-
-;;;; Caption and Labels
-
-
-(defun org-e-odt--wrap-label (element output)
- "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
-This function shouldn't be used for floats. See
-`org-e-odt--caption/label-string'."
- ;; (let ((label (org-element-property :name element)))
- ;; (if (or (not output) (not label) (string= output "") (string= label ""))
- ;; output
- ;; (concat (format "\\label{%s}\n" label) output)))
- output)
-
-
-(defun org-e-odt--caption/label-string (caption label info)
- "Return caption and label HTML string for floats.
-
-CAPTION is a cons cell of secondary strings, the car being the
-standard caption and the cdr its short form. LABEL is a string
-representing the label. INFO is a plist holding contextual
-information.
-
-If there's no caption nor label, return the empty string.
-
-For non-floats, see `org-e-odt--wrap-label'."
- (setq label nil) ;; FIXME
-
- (let ((label-str (if label (format "\\label{%s}" label) "")))
- (cond
- ((and (not caption) (not label)) "")
- ((not caption) (format "\\label{%s}\n" label))
- ;; Option caption format with short name.
- ((cdr caption)
- (format "\\caption[%s]{%s%s}\n"
- (org-export-data (cdr caption) info)
- label-str
- (org-export-data (car caption) info)))
- ;; Standard caption format.
- ;; (t (format "\\caption{%s%s}\n"
- ;; label-str
- ;; (org-export-data (car caption) info)))
- (t (org-export-data (car caption) info)))))
-
-;;;; Checkbox
-
-(defun org-e-odt--checkbox (item)
- "Return check-box string associated to ITEM."
- (let ((checkbox (org-element-property :checkbox item)))
- (if (not checkbox) ""
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgCode" (case checkbox
- (on "[&#x2713;] ") ; CHECK MARK
- (off "[ ] ")
- (trans "[-] "))))))
-
-
-
-;;; Template
-
-(defun org-e-odt-template (contents info)
- "Return complete document string after HTML conversion.
-CONTENTS is the transcoded contents string. RAW-DATA is the
-original parsed data. INFO is a plist holding export options."
- ;; Write meta file.
- (let ((title (org-export-data (plist-get info :title) info))
- (author (let ((author (plist-get info :author)))
- (if (not author) "" (org-export-data author info))))
- (date (org-e-odt--date
- (org-export-data (plist-get info :date) info)))
- (email (plist-get info :email))
- (keywords (plist-get info :keywords))
- (description (plist-get info :description)))
- (write-region
- (concat
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
- <office:document-meta
- xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"
- xmlns:xlink=\"http://www.w3.org/1999/xlink\"
- xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
- xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"
- xmlns:ooo=\"http://openoffice.org/2004/office\"
- office:version=\"1.2\">
- <office:meta>\n"
- (format "<dc:creator>%s</dc:creator>\n" author)
- (format "<meta:initial-creator>%s</meta:initial-creator>\n" author)
- (format "<dc:date>%s</dc:date>\n" date)
- (format "<meta:creation-date>%s</meta:creation-date>\n" date)
- (format "<meta:generator>%s</meta:generator>\n"
- (let ((creator-info (plist-get info :with-creator)))
- (if (or (not creator-info) (eq creator-info 'comment)) ""
- (plist-get info :creator))))
- (format "<meta:keyword>%s</meta:keyword>\n" keywords)
- (format "<dc:subject>%s</dc:subject>\n" description)
- (format "<dc:title>%s</dc:title>\n" title)
- "\n"
- " </office:meta>\n" "</office:document-meta>")
- nil (concat org-e-odt-zip-dir "meta.xml"))
- ;; Add meta.xml in to manifest.
- (org-e-odt-create-manifest-file-entry "text/xml" "meta.xml"))
-
- ;; Update styles file.
- ;; Copy styles.xml. Also dump htmlfontify styles, if there is any.
- ;; Write styles file.
- (let* ((styles-file (plist-get info :odt-styles-file))
- (styles-file (and styles-file (read (org-trim styles-file))))
- ;; Non-availability of styles.xml is not a critical
- ;; error. For now throw an error purely for aesthetic
- ;; reasons.
- (styles-file (or styles-file
- org-e-odt-styles-file
- (expand-file-name "OrgOdtStyles.xml"
- org-e-odt-styles-dir)
- (error "org-e-odt: Missing styles file?"))))
- (cond
- ((listp styles-file)
- (let ((archive (nth 0 styles-file))
- (members (nth 1 styles-file)))
- (org-e-odt--zip-extract archive members org-e-odt-zip-dir)
- (mapc
- (lambda (member)
- (when (org-file-image-p member)
- (let* ((image-type (file-name-extension member))
- (media-type (format "image/%s" image-type)))
- (org-e-odt-create-manifest-file-entry media-type member))))
- members)))
- ((and (stringp styles-file) (file-exists-p styles-file))
- (let ((styles-file-type (file-name-extension styles-file)))
- (cond
- ((string= styles-file-type "xml")
- (copy-file styles-file (concat org-e-odt-zip-dir "styles.xml") t))
- ((member styles-file-type '("odt" "ott"))
- (org-e-odt--zip-extract styles-file "styles.xml" org-e-odt-zip-dir)))))
- (t
- (error (format "Invalid specification of styles.xml file: %S"
- org-e-odt-styles-file))))
-
- ;; create a manifest entry for styles.xml
- (org-e-odt-create-manifest-file-entry "text/xml" "styles.xml")
-
- ;; FIXME: Who is opening an empty styles.xml before this point?
- (with-current-buffer
- (find-file-noselect (concat org-e-odt-zip-dir "styles.xml") t)
- (revert-buffer t t)
-
- ;; Write custom styles for source blocks
- ;; Save STYLES used for colorizing of source blocks.
- ;; Update styles.xml with styles that were collected as part of
- ;; `org-e-odt-hfy-face-to-css' callbacks.
- (let ((styles (mapconcat (lambda (style) (format " %s\n" (cddr style)))
- hfy-user-sheet-assoc "")))
- (when styles
- (goto-char (point-min))
- (when (re-search-forward "</office:styles>" nil t)
- (goto-char (match-beginning 0))
- (insert "\n<!-- Org Htmlfontify Styles -->\n" styles "\n"))))
-
- ;; Update styles.xml - take care of outline numbering
-
- ;; Don't make automatic backup of styles.xml file. This setting
- ;; prevents the backed-up styles.xml file from being zipped in to
- ;; odt file. This is more of a hackish fix. Better alternative
- ;; would be to fix the zip command so that the output odt file
- ;; includes only the needed files and excludes any auto-generated
- ;; extra files like backups and auto-saves etc etc. Note that
- ;; currently the zip command zips up the entire temp directory so
- ;; that any auto-generated files created under the hood ends up in
- ;; the resulting odt file.
- (set (make-local-variable 'backup-inhibited) t)
-
- ;; Outline numbering is retained only upto LEVEL.
- ;; To disable outline numbering pass a LEVEL of 0.
-
- (goto-char (point-min))
- (let ((regex
- "<text:outline-level-style\\([^>]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>")
- (replacement
- "<text:outline-level-style\\1text:level=\"\\2\" style:num-format=\"\">"))
- (while (re-search-forward regex nil t)
- (unless (let ((sec-num (plist-get info :section-numbers))
- (level (string-to-number (match-string 2))))
- (if (wholenump sec-num) (<= level sec-num) sec-num))
- (replace-match replacement t nil))))
- (save-buffer 0)))
- ;; Update content.xml.
- (with-temp-buffer
- (insert-file-contents
- (or org-e-odt-content-template-file
- (expand-file-name "OrgOdtContentTemplate.xml"
- org-e-odt-styles-dir)))
- ;; Write automatic styles.
- ;; - Position the cursor.
- (goto-char (point-min))
- (re-search-forward " </office:automatic-styles>" nil t)
- (goto-char (match-beginning 0))
- ;; - Dump automatic table styles
- (loop for (style-name props) in
- (plist-get org-e-odt-automatic-styles 'Table) do
- (when (setq props (or (plist-get props :rel-width) 96))
- (insert (format org-e-odt-table-style-format style-name props))))
- ;; Update display level.
- ;; - Remove existing sequence decls. Also position the cursor.
- (goto-char (point-min))
- (when (re-search-forward "<text:sequence-decls" nil t)
- (delete-region (match-beginning 0)
- (re-search-forward "</text:sequence-decls>" nil nil)))
- ;; Update sequence decls according to user preference.
- (insert
- (format
- "\n<text:sequence-decls>\n%s\n</text:sequence-decls>"
- (mapconcat
- (lambda (x)
- (format
- "<text:sequence-decl text:display-outline-level=\"%d\" text:name=\"%s\"/>"
- org-e-odt-display-outline-level (nth 1 x)))
- org-e-odt-category-map-alist "\n")))
- ;; Position the cursor to document body.
- (goto-char (point-min))
- (re-search-forward "</office:text>" nil nil)
- (goto-char (match-beginning 0))
-
- ;; Preamble - Title, Author, Date etc.
- (insert
- (let* ((title (org-export-data (plist-get info :title) info))
- (author (and (plist-get info :with-author)
- (let ((auth (plist-get info :author)))
- (and auth (org-export-data auth info)))))
- (date (org-export-data (plist-get info :date) info))
- (iso-date (org-e-odt--date date))
- (date (org-e-odt--date date "%d %b %Y"))
- (email (plist-get info :email))
- ;; switch on or off above vars based on user settings
- (author (and (plist-get info :with-author) (or author email)))
- ;; (date (and (plist-get info :time-stamp-file) date))
- (email (and (plist-get info :with-email) email)))
- (concat
- ;; title
- (when title
- (concat
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "OrgTitle" (format "\n<text:title>%s</text:title>" title))
- ;; separator
- "\n<text:p text:style-name=\"OrgTitle\"/>"))
- (cond
- ((and author (not email))
- ;; author only
- (concat
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "OrgSubtitle"
- (format "<text:initial-creator>%s</text:initial-creator>" author))
- ;; separator
- "\n<text:p text:style-name=\"OrgSubtitle\"/>"))
- ((and author email)
- ;; author and email
- (concat
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "OrgSubtitle"
- (org-e-odt-format-link
- (format "<text:initial-creator>%s</text:initial-creator>" author)
- (concat "mailto:" email)))
- ;; separator
- "\n<text:p text:style-name=\"OrgSubtitle\"/>")))
- ;; date
- (when date
- (concat
- (format
- "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "OrgSubtitle"
- (format
- "\n<text:date style:data-style-name=\"%s\" text:date-value=\"%s\">%s</text:date>"
-
- "N75" iso-date date))
- ;; separator
- "<text:p text:style-name=\"OrgSubtitle\"/>")))))
-
- ;; Table of Contents
- (let ((depth (plist-get info :with-toc)))
- (when (wholenump depth) (insert (org-e-odt-toc depth info))))
- ;; Contents.
- (insert contents)
- ;; Return contents.
- (buffer-substring-no-properties (point-min) (point-max))))
-
-
-
-;;; Transcode Functions
-
-;;;; Bold
-
-(defun org-e-odt-bold (bold contents info)
- "Transcode BOLD from Org to ODT.
-CONTENTS is the text with bold markup. INFO is a plist holding
-contextual information."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "Bold" contents))
-
-
-;;;; Center Block
-
-(defun org-e-odt-center-block (center-block contents info)
- "Transcode a CENTER-BLOCK element from Org to ODT.
-CONTENTS holds the contents of the center block. INFO is a plist
-holding contextual information."
- (org-e-odt--wrap-label center-block contents))
-
-
-;;;; Clock
-
-(defun org-e-odt-clock (clock contents info)
- "Transcode a CLOCK element from Org to ODT.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestampWrapper"
- (concat
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestampKeyword" org-clock-string)
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestamp"
- (concat (org-translate-time
- (org-element-property :value clock))
- (let ((time (org-element-property :time clock)))
- (and time (format " (%s)" time))))))))
-
-
-;;;; Code
-
-(defun org-e-odt-code (code contents info)
- "Transcode a CODE object from Org to ODT.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgCode" (org-element-property :value code)))
-
-
-;;;; Comment
-
-;; Comments are ignored.
-
-
-;;;; Comment Block
-
-;; Comment Blocks are ignored.
-
-
-;;;; Drawer
-
-(defun org-e-odt-drawer (drawer contents info)
- "Transcode a DRAWER element from Org to ODT.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let* ((name (org-element-property :drawer-name drawer))
- (output (if (functionp org-e-odt-format-drawer-function)
- (funcall org-e-odt-format-drawer-function
- name contents)
- ;; If there's no user defined function: simply
- ;; display contents of the drawer.
- contents)))
- (org-e-odt--wrap-label drawer output)))
-
-
-;;;; Dynamic Block
-
-(defun org-e-odt-dynamic-block (dynamic-block contents info)
- "Transcode a DYNAMIC-BLOCK element from Org to ODT.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information. See `org-export-data'."
- (org-e-odt--wrap-label dynamic-block contents))
-
-
-;;;; Entity
-
-(defun org-e-odt-entity (entity contents info)
- "Transcode an ENTITY object from Org to ODT.
-CONTENTS are the definition itself. INFO is a plist holding
-contextual information."
- ;; (let ((ent (org-element-property :latex entity)))
- ;; (if (org-element-property :latex-math-p entity)
- ;; (format "$%s$" ent)
- ;; ent))
- (org-element-property :utf-8 entity))
-
-
-;;;; Example Block
-
-(defun org-e-odt-example-block (example-block contents info)
- "Transcode a EXAMPLE-BLOCK element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-odt--wrap-label
- example-block (org-e-odt-format-code example-block info)))
-
-
-;;;; Export Snippet
-
-(defun org-e-odt-export-snippet (export-snippet contents info)
- "Transcode a EXPORT-SNIPPET object from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (eq (org-export-snippet-backend export-snippet) 'e-odt)
- (org-element-property :value export-snippet)))
-
-
-;;;; Export Block
-
-(defun org-e-odt-export-block (export-block contents info)
- "Transcode a EXPORT-BLOCK element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (string= (org-element-property :type export-block) "ODT")
- (org-remove-indentation (org-element-property :value export-block))))
-
-
-;;;; Fixed Width
-
-(defun org-e-odt-fixed-width (fixed-width contents info)
- "Transcode a FIXED-WIDTH element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-odt--wrap-label
- fixed-width (org-e-odt-do-format-code
- (org-element-property :value fixed-width))))
-
-
-;;;; Footnote Definition
-
-;; Footnote Definitions are ignored.
-
-
-;;;; Footnote Reference
-
-(defun org-e-odt-footnote-reference (footnote-reference contents info)
- "Transcode a FOOTNOTE-REFERENCE element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((--format-footnote-definition
- (function
- (lambda (n def)
- (setq n (format "%d" n))
- (let ((id (concat "fn" n))
- (note-class "footnote")
- (par-style "Footnote"))
- (format
- "<text:note text:id=\"%s\" text:note-class=\"%s\">%s</text:note>"
- id note-class
- (concat
- (format "<text:note-citation>%s</text:note-citation>" n)
- (format "<text:note-body>%s</text:note-body>" def)))))))
- (--format-footnote-reference
- (function
- (lambda (n)
- (setq n (format "%d" n))
- (let ((note-class "footnote")
- (ref-format "text")
- (ref-name (concat "fn" n)))
- (format
- "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgSuperscript"
- (format "<text:note-ref text:note-class=\"%s\" text:reference-format=\"%s\" text:ref-name=\"%s\">%s</text:note-ref>"
- note-class ref-format ref-name n)))))))
- (concat
- ;; Insert separator between two footnotes in a row.
- (let ((prev (org-export-get-previous-element footnote-reference info)))
- (and (eq (org-element-type prev) 'footnote-reference)
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgSuperscript" ",")))
- ;; Trancode footnote reference.
- (let ((n (org-export-get-footnote-number footnote-reference info)))
- (cond
- ((not (org-export-footnote-first-reference-p footnote-reference info))
- (funcall --format-footnote-reference n))
- ;; Inline definitions are secondary strings.
- ;; Non-inline footnotes definitions are full Org data.
- (t
- (let* ((raw (org-export-get-footnote-definition footnote-reference
- info))
- (def (let ((def (org-trim (org-export-data raw info))))
- (if (eq (org-element-type raw) 'org-data) def
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Footnote" def)))))
- (funcall --format-footnote-definition n def))))))))
-
-
-;;;; Headline
-
-(defun* org-e-odt-format-headline
- (todo todo-type priority text tags
- &key level section-number headline-label &allow-other-keys)
- (concat
- ;; Todo.
- (and todo
- (concat
- (let ((style (if (member todo org-done-keywords) "OrgDone" "OrgTodo")))
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- style todo)) " "))
- ;; Title.
- text
- ;; Tags.
- (and tags
- (concat "<text:tab/>"
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTag" (mapconcat 'org-trim tags " : "))))))
-
-(defun org-e-odt-format-headline--wrap (headline info
- &optional format-function
- &rest extra-keys)
- "Transcode an HEADLINE element from Org to ODT.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- (let* ((level (+ (org-export-get-relative-level headline info)))
- (headline-number (org-export-get-headline-number headline info))
- (section-number (and (org-export-numbered-headline-p headline info)
- (mapconcat 'number-to-string
- headline-number ".")))
- (todo (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword headline)))
- (and todo (org-export-data todo info)))))
- (todo-type (and todo (org-element-property :todo-type headline)))
- (priority (and (plist-get info :with-priority)
- (org-element-property :priority headline)))
- (text (org-export-data (org-element-property :title headline) info))
- (tags (and (plist-get info :with-tags)
- (org-export-get-tags headline info)))
- (headline-label (concat "sec-" (mapconcat 'number-to-string
- headline-number "-")))
- (format-function (cond
- ((functionp format-function) format-function)
- ((functionp org-e-odt-format-headline-function)
- (function*
- (lambda (todo todo-type priority text tags
- &allow-other-keys)
- (funcall org-e-odt-format-headline-function
- todo todo-type priority text tags))))
- (t 'org-e-odt-format-headline))))
- (apply format-function
- todo todo-type priority text tags
- :headline-label headline-label :level level
- :section-number section-number extra-keys)))
-
-
-(defun org-e-odt-begin-plain-list (ltype &optional continue-numbering)
- (unless (member ltype '(ordered unordered descriptive))
- (error "Unknown list type: %s" ltype))
- (let ((style-name (assoc-default ltype
- '((ordered . "OrgNumberedList")
- (unordered . "OrgBulletedList")
- (descriptive . "OrgDescriptionList")))))
- (format "<text:list text:style-name=\"%s\" text:continue-numbering=\"%s\">"
- style-name (if continue-numbering "true" "false"))))
-
-(defun org-e-odt-headline (headline contents info)
- "Transcode an HEADLINE element from Org to ODT.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- (let* ((numberedp (org-export-numbered-headline-p headline info))
- ;; Get level relative to current parsed data.
- (level (org-export-get-relative-level headline info))
- (text (org-export-data (org-element-property :title headline) info))
- ;; Create the headline text.
- (full-text (org-e-odt-format-headline--wrap headline info)))
- (cond
- ;; Case 1: This is a footnote section: ignore it.
- ((org-element-property :footnote-section-p headline) nil)
- ;; Case 2. This is a deep sub-tree: export it as a list item.
- ;; Also export as items headlines for which no section
- ;; format has been found.
- ;; FIXME
- ;; ((org-export-low-level-p headline info)
- ;; ;; Build the real contents of the sub-tree.
- ;; (let* ((type (if numberedp 'unordered 'unordered)) ; FIXME
- ;; (itemized-body (org-e-odt-format-list-item
- ;; contents type nil nil full-text)))
- ;; (concat
- ;; (and (org-export-first-sibling-p headline info)
- ;; (org-e-odt-begin-plain-list type))
- ;; itemized-body
- ;; (and (org-export-last-sibling-p headline info)
- ;; "</text:list>"))))
- ;; Case 3. Standard headline. Export it as a section.
- (t
- (let* ((extra-ids (list (org-element-property :custom-id headline)
- (org-element-property :id headline)))
- (extra-ids nil) ; FIXME
- (id (concat "sec-" (mapconcat 'number-to-string
- (org-export-get-headline-number
- headline info) "-"))))
- (concat
- (format
- "\n<text:h text:style-name=\"%s\" text:outline-level=\"%s\">%s%s</text:h>"
- (format "Heading_20_%s" level)
- level
- ;; Extra targets.
- (mapconcat (lambda (x)
- (when x
- (let ((x (if (org-uuidgen-p x) (concat "ID-" x) x)))
- (org-e-odt-format-target
- "" (org-export-solidify-link-text x)))))
- extra-ids "")
- ;; Title.
- (org-e-odt-format-target full-text id))
- contents))))))
-
-
-;;;; Horizontal Rule
-
-(defun org-e-odt-horizontal-rule (horizontal-rule contents info)
- "Transcode an HORIZONTAL-RULE object from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-odt--wrap-label
- horizontal-rule
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Horizontal_20_Line" "")))
-
-
-;;;; Inline Babel Call
-
-;; Inline Babel Calls are ignored.
-
-
-;;;; Inline Src Block
-
-(defun org-e-odt--find-verb-separator (s)
- "Return a character not used in string S.
-This is used to choose a separator for constructs like \\verb."
- (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
- (loop for c across ll
- when (not (string-match (regexp-quote (char-to-string c)) s))
- return (char-to-string c))))
-
-(defun org-e-odt-inline-src-block (inline-src-block contents info)
- "Transcode an INLINE-SRC-BLOCK element from Org to ODT.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((org-lang (org-element-property :language inline-src-block))
- (code (org-element-property :value inline-src-block))
- (separator (org-e-odt--find-verb-separator code)))
- (error "FIXME")))
-
-
-;;;; Inlinetask
-
-(defun org-e-odt-inlinetask (inlinetask contents info)
- "Transcode an INLINETASK element from Org to ODT.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (cond
- ;; If `org-e-odt-format-inlinetask-function' is provided, call it
- ;; with appropriate arguments.
- ((functionp org-e-odt-format-inlinetask-function)
- (let ((format-function
- (function*
- (lambda (todo todo-type priority text tags
- &key contents &allow-other-keys)
- (funcall org-e-odt-format-inlinetask-function
- todo todo-type priority text tags contents)))))
- (org-e-odt-format-headline--wrap
- inlinetask info format-function :contents contents)))
- ;; Otherwise, use a default template.
- (t (org-e-odt--wrap-label
- inlinetask
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Text_20_body"
- (org-e-odt--textbox
- (concat
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "OrgInlineTaskHeading"
- (org-e-odt-format-headline--wrap
- inlinetask info))
- contents)
- nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\""))))))
-
-;;;; Italic
-
-(defun org-e-odt-italic (italic contents info)
- "Transcode ITALIC from Org to ODT.
-CONTENTS is the text with italic markup. INFO is a plist holding
-contextual information."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "Emphasis" contents))
-
-
-;;;; Item
-
-(defun org-e-odt-item (item contents info)
- "Transcode an ITEM element from Org to ODT.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((plain-list (org-export-get-parent item))
- (type (org-element-property :type plain-list))
- (counter (org-element-property :counter item))
- (tag (let ((tag (org-element-property :tag item)))
- (and tag
- (concat (org-e-odt--checkbox item)
- (org-export-data tag info))))))
- (case type
- ((ordered unordered)
- (format "\n<text:list-item>\n%s\n%s"
- contents
- (let* ((--element-has-a-table-p
- (function
- (lambda (element info)
- (loop for el in (org-element-contents element)
- thereis (eq (org-element-type el) 'table))))))
- (cond
- ((funcall --element-has-a-table-p item info)
- "</text:list-header>")
- (t "</text:list-item>")))))
- (descriptive
- (concat
- (let ((term (or tag "(no term)")))
- (concat
- (format "\n<text:list-item>\n%s\n</text:list-item>"
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Text_20_body_20_bold" term))
- (format
- "\n<text:list-item>\n%s\n</text:list-item>"
- (format "\n<text:list text:style-name=\"%s\" %s>\n%s\n</text:list>"
- "OrgDescriptionList"
- "text:continue-numbering=\"false\""
- (format "\n<text:list-item>\n%s\n</text:list-item>"
- contents)))))))
- (t (error "Unknown list type: %S" type)))))
-
-
-;;;; Keyword
-
-(defun org-e-odt-keyword (keyword contents info)
- "Transcode a KEYWORD element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((key (org-element-property :key keyword))
- (value (org-element-property :value keyword)))
- (cond
- ((string= key "LATEX") value)
- ((string= key "INDEX") (format "\\index{%s}" value))
- ((string= key "TARGET") nil ; FIXME
- ;; (format "\\label{%s}" (org-export-solidify-link-text value))
- )
- ((string= key "toc")
- (let ((value (downcase value)))
- (cond
- ((string-match "\\<headlines\\>" value)
- (let ((depth (or (and (string-match "[0-9]+" value)
- (string-to-number (match-string 0 value)))
- (plist-get info :with-toc))))
- (when (wholenump depth) (org-e-odt-toc depth info))))
- ((string= "tables" value) "FIXME")
- ((string= "figures" value) "FIXME")
- ((string= "listings" value)
- (cond
- ;; At the moment, src blocks with a caption are wrapped
- ;; into a figure environment.
- (t "FIXME")))))))))
-
-
-;;;; Latex Environment
-
-
-(eval-after-load 'org-odt
- '(ad-deactivate 'org-format-latex-as-mathml))
-
-;; (defadvice org-format-latex-as-mathml ; FIXME
-;; (after org-e-odt-protect-latex-fragment activate)
-;; "Encode LaTeX fragment as XML.
-;; Do this when translation to MathML fails."
-;; (when (or (not (> (length ad-return-value) 0))
-;; (get-text-property 0 'org-protected ad-return-value))
-;; (setq ad-return-value
-;; (org-propertize (org-e-odt-encode-plain-text (ad-get-arg 0))
-;; 'org-protected t))))
-
-(defun org-e-odt-format-latex (latex-frag processing-type info)
- (let* ((prefix (case processing-type
- (dvipng "ltxpng/")
- (mathml "ltxmathml/")))
- (input-file (plist-get info :input-file))
- (cache-subdir
- (concat prefix (file-name-sans-extension
- (file-name-nondirectory input-file))))
- (cache-dir (file-name-directory input-file))
- (display-msg (case processing-type
- (dvipng "Creating LaTeX Image...")
- (mathml "Creating MathML snippet..."))))
- (with-temp-buffer
- (insert latex-frag)
- (org-format-latex cache-subdir cache-dir nil display-msg
- nil nil processing-type)
- (buffer-string))))
-
-(defun org-e-odt-latex-environment (latex-environment contents info)
- "Transcode a LATEX-ENVIRONMENT element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-odt--wrap-label
- latex-environment
- (let* ((latex-frag
- (org-remove-indentation
- (org-element-property :value latex-environment)))
- (processing-type (plist-get info :LaTeX-fragments))
- (caption (org-element-property :caption latex-environment))
- (short-caption (and (cdr caption)
- (org-export-data (cdr caption) info)))
- (caption (and (car caption) (org-export-data (car caption) info)))
- (label (org-element-property :name latex-environment))
- (attr nil) ; FIXME
- (label (org-element-property :name latex-environment)))
-
- (when (memq processing-type '(t mathjax))
- (unless (and (fboundp 'org-format-latex-mathml-available-p)
- (org-format-latex-mathml-available-p))
- (message "LaTeX to MathML converter not available. Trying dvinpng...")
- (setq processing-type 'dvipng)))
-
- (when (eq processing-type 'dvipng)
- (unless (and (org-check-external-command "latex" "" t)
- (org-check-external-command "dvipng" "" t))
- (message "LaTeX to PNG converter not available. Using verbatim.")
- (setq processing-type 'verbatim)))
-
- (case processing-type
- ((t mathjax)
- (org-e-odt-format-formula latex-environment info))
- (dvipng
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Text_20_body"
- (org-e-odt-link--inline-image latex-environment info)))
- (t (org-e-odt-do-format-code latex-frag))))))
-
-
-;;;; Latex Fragment
-
-
-;; (when latex-frag ; FIXME
-;; (setq href (org-propertize href :title "LaTeX Fragment"
-;; :description latex-frag)))
-;; handle verbatim
-;; provide descriptions
-
-(defun org-e-odt-latex-fragment (latex-fragment contents info)
- "Transcode a LATEX-FRAGMENT object from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let* ((latex-frag (org-element-property :value latex-fragment))
- (processing-type (plist-get info :LaTeX-fragments)))
- (cond
- ((member processing-type '(t mathjax))
- (org-e-odt-format-formula latex-fragment info))
- ((eq processing-type 'dvipng)
- (org-e-odt-link--inline-image latex-fragment info))
- (t (org-e-odt-encode-plain-text latex-frag t)))))
-
-
-;;;; Line Break
-
-(defun org-e-odt-line-break (line-break contents info)
- "Transcode a LINE-BREAK object from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- "<text:line-break/>\n")
-
-
-;;;; Link
-
-
-
-;;;; Links :: Generic
-
-(defun org-e-odt-format-link (desc href &optional suppress-xref)
- (cond
- ((and (= (string-to-char href) ?#) (not suppress-xref))
- (setq href (substring href 1))
- (let ((xref-format "text"))
- (when (numberp desc)
- (setq desc (format "%d" desc) xref-format "number"))
- (when (listp desc)
- (setq desc (mapconcat 'number-to-string desc ".") xref-format "chapter"))
- (setq href (concat org-e-odt-bookmark-prefix href))
- (format
- "<text:bookmark-ref text:reference-format=\"%s\" text:ref-name=\"%s\">%s</text:bookmark-ref>"
- xref-format href desc)))
- ;; (org-lparse-link-description-is-image
- ;; (format "\n<draw:a xlink:type=\"simple\" xlink:href=\"%s\">\n%s\n</draw:a>"
- ;; href desc))
- (t (format "<text:a xlink:type=\"simple\" xlink:href=\"%s\">%s</text:a>"
- href desc))))
-
-(defun org-e-odt-format-internal-link (text href)
- (org-e-odt-format-link text (concat "#" href)))
-
-;;;; Links :: Label references
-
-(defun org-e-odt-enumerate-element (element info &optional predicate n)
- (let* ((--numbered-parent-headline-at-<=-n
- (function
- (lambda (element n info)
- (loop for x in (org-export-get-genealogy element)
- thereis (and (eq (org-element-type x) 'headline)
- (<= (org-export-get-relative-level x info) n)
- (org-export-numbered-headline-p x info)
- x)))))
- (--enumerate
- (function
- (lambda (element scope info &optional predicate)
- (let ((counter 0))
- (org-element-map
- (or scope (plist-get info :parse-tree))
- (org-element-type element)
- (lambda (el)
- (and (or (not predicate) (funcall predicate el info))
- (incf counter)
- (eq element el)
- counter))
- info 'first-match)))))
- (scope (funcall --numbered-parent-headline-at-<=-n
- element (or n org-e-odt-display-outline-level) info))
- (ordinal (funcall --enumerate element scope info predicate))
- (tag
- (concat
- ;; Section number.
- (and scope
- (mapconcat 'number-to-string
- (org-export-get-headline-number scope info) "."))
- ;; Separator.
- (and scope ".")
- ;; Ordinal.
- (number-to-string ordinal))))
- tag))
-
-(defun org-e-odt-format-label (element info op)
- (let* ((caption-from
- (case (org-element-type element)
- (link (org-export-get-parent-element element))
- (t element)))
- ;; get label and caption.
- (label (org-element-property :name caption-from))
- (caption (org-element-property :caption caption-from))
- (short-caption (cdr caption))
- ;; transcode captions.
- (caption (and (car caption) (org-export-data (car caption) info)))
- (short-caption (and short-caption
- (org-export-data short-caption info))))
- (when (or label caption)
- (let* ((default-category
- (cond
- ((eq (org-element-type element) 'table)
- "__Table__")
- ((org-e-odt-standalone-image-p element info)
- "__Figure__")
- ((member (org-element-type element)
- '(latex-environment latex-fragment))
- (let ((processing-type (plist-get info :LaTeX-fragments)))
- (cond
- ((eq processing-type 'dvipng) "__DvipngImage__")
- ((eq processing-type 'mathjax) "__MathFormula__")
- ((eq processing-type 't) "__MathFormula__")
- (t (error "Handle LaTeX:verbatim")))))
- ((eq (org-element-type element) 'src-block)
- "__Listing__")
- (t (error "Handle enumeration of %S" element))))
- (predicate
- (cond
- ((member (org-element-type element)
- '(table latex-environment src-block))
- nil)
- ((org-e-odt-standalone-image-p element info)
- 'org-e-odt-standalone-image-p)
- (t (error "Handle enumeration of %S" element))))
- (seqno (org-e-odt-enumerate-element
- element info predicate)) ; FIXME
- ;; handle label props.
- (label-props (assoc default-category org-e-odt-category-map-alist))
- ;; identify opendocument counter
- (counter (nth 1 label-props))
- ;; identify label style
- (label-style (nth 2 label-props))
- ;; retrieve localized category sting
- (category (org-export-translate (nth 3 label-props) :utf-8 info)))
- (case op
- (definition
- ;; assign an internal label, if user has not provided one
- (setq label (or label (format "%s-%s" default-category seqno)))
- (setq label (org-export-solidify-link-text label))
-
- (cons
- (format-spec
- (cadr (assoc-string label-style org-e-odt-label-styles t))
- `((?e . ,category)
- (?n . ,(format
- "<text:sequence text:ref-name=\"%s\" text:name=\"%s\" text:formula=\"ooow:%s+1\" style:num-format=\"1\">%s</text:sequence>"
- label counter counter seqno))
- (?c . ,(or caption ""))))
- short-caption))
- (reference
- (assert label)
- (setq label (org-export-solidify-link-text label))
- (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t)))
- (fmt1 (car fmt))
- (fmt2 (cadr fmt)))
- (format "<text:sequence-ref text:reference-format=\"%s\" text:ref-name=\"%s\">%s</text:sequence-ref>"
- fmt1 label (format-spec fmt2 `((?e . ,category)
- (?n . ,seqno))))))
- (t (error "Unknow %S on label" op)))))))
-
-;;;; Links :: Embedded images
-
-(defun org-e-odt-copy-image-file (path)
- "Returns the internal name of the file"
- (let* ((image-type (file-name-extension path))
- (media-type (format "image/%s" image-type))
- (target-dir "Images/")
- (target-file
- (format "%s%04d.%s" target-dir
- (incf org-e-odt-embedded-images-count) image-type)))
- (message "Embedding %s as %s ..."
- (substring-no-properties path) target-file)
-
- (when (= 1 org-e-odt-embedded-images-count)
- (make-directory (concat org-e-odt-zip-dir target-dir))
- (org-e-odt-create-manifest-file-entry "" target-dir))
-
- (copy-file path (concat org-e-odt-zip-dir target-file) 'overwrite)
- (org-e-odt-create-manifest-file-entry media-type target-file)
- target-file))
-
-(defun org-e-odt-image-size-from-file (file &optional user-width
- user-height scale dpi embed-as)
- (let* ((--pixels-to-cms
- (function (lambda (pixels dpi)
- (let ((cms-per-inch 2.54)
- (inches (/ pixels dpi)))
- (* cms-per-inch inches)))))
- (--size-in-cms
- (function
- (lambda (size-in-pixels dpi)
- (and size-in-pixels
- (cons (funcall --pixels-to-cms (car size-in-pixels) dpi)
- (funcall --pixels-to-cms (cdr size-in-pixels) dpi))))))
- (dpi (or dpi org-e-odt-pixels-per-inch))
- (anchor-type (or embed-as "paragraph"))
- (user-width (and (not scale) user-width))
- (user-height (and (not scale) user-height))
- (size
- (and
- (not (and user-height user-width))
- (or
- ;; Use Imagemagick.
- (and (executable-find "identify")
- (let ((size-in-pixels
- (let ((dim (shell-command-to-string
- (format "identify -format \"%%w:%%h\" \"%s\""
- file))))
- (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim)
- (cons (string-to-number (match-string 1 dim))
- (string-to-number (match-string 2 dim)))))))
- (funcall --size-in-cms size-in-pixels dpi)))
- ;; Use Emacs.
- (let ((size-in-pixels
- (ignore-errors ; Emacs could be in batch mode
- (clear-image-cache)
- (image-size (create-image file) 'pixels))))
- (funcall --size-in-cms size-in-pixels dpi))
- ;; Use hard-coded values.
- (cdr (assoc-string anchor-type
- org-e-odt-default-image-sizes-alist))
- ;; Error out.
- (error "Cannot determine image size, aborting"))))
- (width (car size)) (height (cdr size)))
- (cond
- (scale
- (setq width (* width scale) height (* height scale)))
- ((and user-height user-width)
- (setq width user-width height user-height))
- (user-height
- (setq width (* user-height (/ width height)) height user-height))
- (user-width
- (setq height (* user-width (/ height width)) width user-width))
- (t (ignore)))
- ;; ensure that an embedded image fits comfortably within a page
- (let ((max-width (car org-e-odt-max-image-size))
- (max-height (cdr org-e-odt-max-image-size)))
- (when (or (> width max-width) (> height max-height))
- (let* ((scale1 (/ max-width width))
- (scale2 (/ max-height height))
- (scale (min scale1 scale2)))
- (setq width (* scale width) height (* scale height)))))
- (cons width height)))
-
-;;;; Links :: Math formula
-
-(defun org-e-odt-format-formula (element info)
- (let* ((src (cond
- ((eq (org-element-type element) 'link) ; FIXME
- (let* ((type (org-element-property :type element))
- (raw-path (org-element-property :path element)))
- (cond
- ((file-name-absolute-p raw-path)
- (expand-file-name raw-path))
- (t raw-path))))
- ((member (org-element-type element)
- '(latex-fragment latex-environment))
- (let* ((latex-frag (org-remove-indentation
- (org-element-property :value element)))
- (formula-link (org-e-odt-format-latex
- latex-frag 'mathml info)))
- (and formula-link
- (string-match "file:\\([^]]*\\)" formula-link)
- (match-string 1 formula-link))))
- (t (error "what is this?"))))
- (full-src (if (file-name-absolute-p src) src
- (expand-file-name src (file-name-directory
- (plist-get info :input-file)))))
- (caption-from
- (case (org-element-type element)
- (link (org-export-get-parent-element element))
- (t element)))
- (captions (org-e-odt-format-label caption-from info 'definition))
- (caption (car captions))
- (href
- (format "\n<draw:object %s xlink:href=\"%s\" xlink:type=\"simple\"/>"
- " xlink:show=\"embed\" xlink:actuate=\"onLoad\""
- (file-name-directory (org-e-odt-copy-formula-file full-src))))
- (embed-as (if caption 'paragraph 'character))
- width height)
- (cond
- ((eq embed-as 'character)
- (org-e-odt-format-entity "InlineFormula" href width height))
- (t
- (let* ((equation (org-e-odt-format-entity
- "CaptionedDisplayFormula" href width height captions))
- (label
- (let* ((org-e-odt-category-map-alist
- '(("__Table__" "Table" "value")
- ("__Figure__" "Illustration" "value")
- ("__MathFormula__" "Text" "math-label")
- ("__DvipngImage__" "Equation" "value")
- ("__Listing__" "Listing" "value"))))
- (car (org-e-odt-format-label caption-from info 'definition))))
- (formula-tree
- (org-e-odt--adopt-elements
- `(table (:type org :attr_odt (":style \"OrgEquation\"")))
- (org-e-odt--adopt-elements
- `(table-row (:type standard))
- `(table-cell nil "<c8>") `(table-cell nil "<c1>"))
- (org-e-odt--adopt-elements
- `(table-row (:type standard))
- (org-e-odt--adopt-elements
- `(table-cell nil) `(export-block
- (:type "ODT" :value ,equation)))
- (org-e-odt--adopt-elements
- `(table-cell nil) `(export-block
- (:type "ODT" :value ,label))))))
- (formula-info
- (org-export-collect-tree-properties
- formula-tree (org-export-get-environment 'e-odt))))
- (org-export-data formula-tree formula-info))))))
-
-(defun org-e-odt-copy-formula-file (src-file)
- "Returns the internal name of the file"
- (let* ((target-dir (format "Formula-%04d/"
- (incf org-e-odt-embedded-formulas-count)))
- (target-file (concat target-dir "content.xml")))
- ;; Create a directory for holding formula file. Also enter it in
- ;; to manifest.
- (make-directory (concat org-e-odt-zip-dir target-dir))
- (org-e-odt-create-manifest-file-entry
- "application/vnd.oasis.opendocument.formula" target-dir "1.2")
- ;; Copy over the formula file from user directory to zip
- ;; directory.
- (message "Embedding %s as %s ..." src-file target-file)
- (let ((case-fold-search nil))
- (cond
- ;; Case 1: Mathml.
- ((string-match "\\.\\(mathml\\|mml\\)\\'" src-file)
- (copy-file src-file (concat org-e-odt-zip-dir target-file) 'overwrite))
- ;; Case 2: OpenDocument formula.
- ((string-match "\\.odf\\'" src-file)
- (org-e-odt--zip-extract src-file "content.xml"
- (concat org-e-odt-zip-dir target-dir)))
- (t (error "%s is not a formula file" src-file))))
- ;; Enter the formula file in to manifest.
- (org-e-odt-create-manifest-file-entry "text/xml" target-file)
- target-file))
-
-;;;; Targets
-
-(defun org-e-odt-format-target (text id)
- (let ((name (concat org-e-odt-bookmark-prefix id)))
- (concat
- (and id (format "\n<text:bookmark-start text:name=\"%s\"/>" name))
- (concat (and id (format "\n<text:bookmark text:name=\"%s\"/>" id)) text)
- (and id (format "\n<text:bookmark-end text:name=\"%s\"/>" name)))))
-
-(defun org-e-odt-link--inline-image (element info)
- "Return HTML code for an inline image.
-LINK is the link pointing to the inline image. INFO is a plist
-used as a communication channel."
- (let* ((src (cond
- ((eq (org-element-type element) 'link)
- (let* ((type (org-element-property :type element))
- (raw-path (org-element-property :path element)))
- (cond ((member type '("http" "https"))
- (concat type ":" raw-path))
- ((file-name-absolute-p raw-path)
- (expand-file-name raw-path))
- (t raw-path))))
- ((member (org-element-type element)
- '(latex-fragment latex-environment))
- (let* ((latex-frag (org-remove-indentation
- (org-element-property :value element)))
- (formula-link (org-e-odt-format-latex
- latex-frag 'dvipng info)))
- (and formula-link
- (string-match "file:\\([^]]*\\)" formula-link)
- (match-string 1 formula-link))))
- (t (error "what is this?"))))
- (src-expanded (if (file-name-absolute-p src) src
- (expand-file-name src (file-name-directory
- (plist-get info :input-file)))))
- (href (format
- "\n<draw:image xlink:href=\"%s\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>"
- (org-e-odt-copy-image-file src-expanded)))
- ;; extract attributes from #+ATTR_ODT line.
- (attr-from (case (org-element-type element)
- (link (org-export-get-parent-element element))
- (t element)))
- ;; convert attributes to a plist.
- (attr-plist (org-export-read-attribute :attr_odt attr-from))
- ;; handle `:anchor', `:style' and `:attributes' properties.
- (user-frame-anchor
- (car (assoc-string (plist-get attr-plist :anchor)
- '(("as-char") ("paragraph") ("page")) t)))
- (user-frame-style
- (and user-frame-anchor (plist-get attr-plist :style)))
- (user-frame-attrs
- (and user-frame-anchor (plist-get attr-plist :attributes)))
- (user-frame-params
- (list user-frame-style user-frame-attrs user-frame-anchor))
- ;; (embed-as (or embed-as user-frame-anchor "paragraph"))
- ;; extrac
- ;; handle `:width', `:height' and `:scale' properties.
- (size (org-e-odt-image-size-from-file
- src-expanded (plist-get attr-plist :width)
- (plist-get attr-plist :height)
- (plist-get attr-plist :scale) nil ;; embed-as
- "paragraph" ; FIXME
- ))
- (width (car size)) (height (cdr size))
- (embed-as
- (case (org-element-type element)
- ((org-e-odt-standalone-image-p element info) "paragraph")
- (latex-fragment "as-char")
- (latex-environment "paragraph")
- (t "paragraph")))
- (captions (org-e-odt-format-label element info 'definition))
- (caption (car captions)) (short-caption (cdr captions))
- (entity (concat (and caption "Captioned") embed-as "Image")))
- (org-e-odt-format-entity entity href width height
- captions user-frame-params )))
-
-(defun org-e-odt-format-entity (entity href width height &optional
- captions user-frame-params)
- (let* ((caption (car captions)) (short-caption (cdr captions))
- (entity-style (assoc-string entity org-e-odt-entity-frame-styles t))
- default-frame-params frame-params
- (--merge-frame-params
- (function
- (lambda (default-frame-params user-frame-params)
- (if (not user-frame-params) default-frame-params
- (assert (= (length default-frame-params) 3))
- (assert (= (length user-frame-params) 3))
- (loop for user-frame-param in user-frame-params
- for default-frame-param in default-frame-params
- collect (or user-frame-param default-frame-param)))))))
- (cond
- ((not caption)
- (setq default-frame-params (nth 2 entity-style))
- (setq frame-params (funcall --merge-frame-params
- default-frame-params user-frame-params))
- (apply 'org-e-odt--frame href width height frame-params))
- (t
- (setq default-frame-params (nth 3 entity-style))
- (setq frame-params (funcall --merge-frame-params
- default-frame-params user-frame-params))
- (apply 'org-e-odt--textbox
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Illustration"
- (concat
- (apply 'org-e-odt--frame href width height
- (let ((entity-style-1 (copy-sequence
- (nth 2 entity-style))))
- (setcar (cdr entity-style-1)
- (concat
- (cadr entity-style-1)
- (and short-caption
- (format " draw:name=\"%s\" "
- short-caption))))
- entity-style-1))
- caption))
- width height frame-params)))))
-
-(defun org-e-odt-standalone-image-p (element info)
- "Test if ELEMENT is a standalone image for the purpose ODT export.
-INFO is a plist holding contextual information.
-
-Return non-nil, if ELEMENT is of type paragraph and it's sole
-content, save for whitespaces, is a link that qualifies as an
-inline image.
-
-Return non-nil, if ELEMENT is of type link and it's containing
-paragraph has no other content save for leading and trailing
-whitespaces.
-
-Return nil, otherwise.
-
-Bind `org-e-odt-standalone-image-predicate' to constrain
-paragraph further. For example, to check for only captioned
-standalone images, do the following.
-
- \(setq org-e-odt-standalone-image-predicate
- \(lambda \(paragraph\)
- \(org-element-property :caption paragraph\)\)\)
-"
- (let ((--standalone-image-predicate
- (function (lambda (paragraph)
- (or (org-element-property :caption paragraph)
- (org-element-property :name paragraph)))))
- (paragraph (case (org-element-type element)
- (paragraph element)
- (link (and (org-export-inline-image-p
- element org-e-odt-inline-image-rules)
- (org-export-get-parent element)))
- (t nil))))
- (when paragraph
- (assert (eq (org-element-type paragraph) 'paragraph))
- (when (funcall --standalone-image-predicate paragraph)
- (let ((contents (org-element-contents paragraph)))
- (loop for x in contents
- with inline-image-count = 0
- always (cond
- ((eq (org-element-type x) 'plain-text)
- (not (org-string-nw-p x)))
- ((eq (org-element-type x) 'link)
- (when (org-export-inline-image-p
- x org-e-odt-inline-image-rules)
- (= (incf inline-image-count) 1)))
- (t nil))))))))
-
-(defun org-e-odt-link (link desc info)
- "Transcode a LINK object from Org to ODT.
-
-DESC is the description part of the link, or the empty string.
-INFO is a plist holding contextual information. See
-`org-export-data'."
- (let* ((type (org-element-property :type link))
- (raw-path (org-element-property :path link))
- ;; Ensure DESC really exists, or set it to nil.
- (desc (and (not (string= desc "")) desc))
- (imagep (org-export-inline-image-p
- link org-e-odt-inline-image-rules))
- (path (cond
- ((member type '("http" "https" "ftp" "mailto"))
- (concat type ":" raw-path))
- ((string= type "file")
- (when (string-match "\\(.+\\)::.+" raw-path)
- (setq raw-path (match-string 1 raw-path)))
- (if (file-name-absolute-p raw-path)
- (concat "file://" (expand-file-name raw-path))
- (concat "file://" raw-path)))
- (t raw-path)))
- protocol)
- (cond
- ;; Image file.
- ((and (not desc) (org-export-inline-image-p
- link org-e-odt-inline-image-rules))
- (org-e-odt-link--inline-image link info))
- ;; Radio target: Transcode target's contents and use them as
- ;; link's description.
- ((string= type "radio")
- (let ((destination (org-export-resolve-radio-link link info)))
- (when destination
- (org-e-odt-format-internal-link
- (org-export-data (org-element-contents destination) info)
- (org-export-solidify-link-text path)))))
- ;; Links pointing to an headline: Find destination and build
- ;; appropriate referencing command.
- ((member type '("custom-id" "fuzzy" "id"))
- (let ((destination (if (string= type "fuzzy")
- (org-export-resolve-fuzzy-link link info)
- (org-export-resolve-id-link link info))))
- (case (org-element-type destination)
- ;; Fuzzy link points nowhere.
- ('nil
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "Emphasis" (or desc (org-export-data
- (org-element-property
- :raw-link link) info))))
- ;; Fuzzy link points to an invisible target.
- (keyword nil)
- ;; LINK points to an headline. Check if LINK should display
- ;; section numbers.
- (headline
- (let* ((headline-no (org-export-get-headline-number destination info))
- (label (format "sec-%s" (mapconcat 'number-to-string
- headline-no "-")))
- (desc
- ;; Case 1: Headline is numbered and LINK has no
- ;; description or LINK's description matches
- ;; headline's title. Display section number.
- (if (and (org-export-numbered-headline-p destination info)
- (or (not desc)
- (string= desc (org-element-property
- :raw-value destination))))
- headline-no
- ;; Case 2: Either the headline is un-numbered or
- ;; LINK has a custom description. Display LINK's
- ;; description or headline's title.
- (or desc (org-export-data (org-element-property
- :title destination) info)))))
- (org-e-odt-format-internal-link desc label)))
- ;; Fuzzy link points to a target. Do as above.
- (otherwise
- ;; (unless desc
- ;; (setq number (cond
- ;; ((org-e-odt-standalone-image-p destination info)
- ;; (org-export-get-ordinal
- ;; (assoc 'link (org-element-contents destination))
- ;; info 'link 'org-e-odt-standalone-image-p))
- ;; (t (org-export-get-ordinal destination info))))
- ;; (setq desc (when number
- ;; (if (atom number) (number-to-string number)
- ;; (mapconcat 'number-to-string number ".")))))
-
- (let ((label-reference
- (org-e-odt-format-label destination info 'reference)))
- (assert label-reference)
- label-reference)))))
- ;; Coderef: replace link with the reference name or the
- ;; equivalent line number.
- ((string= type "coderef")
- (let* ((fmt (org-export-get-coderef-format path desc))
- (res (org-export-resolve-coderef path info))
- (href (concat "#coderef-" path)))
- (format fmt (org-e-odt-format-link res href))))
- ;; Link type is handled by a special function.
- ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
- (funcall protocol (org-link-unescape path) desc 'odt))
- ;; External link with a description part.
- ((and path desc) (org-e-odt-format-link desc path))
- ;; External link without a description part.
- (path (org-e-odt-format-link path path))
- ;; No path, only description. Try to do something useful.
- (t (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "Emphasis" desc)))))
-
-
-;;;; Babel Call
-
-;; Babel Calls are ignored.
-
-
-;;;; Macro
-
-(defun org-e-odt-macro (macro contents info)
- "Transcode a MACRO element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- ;; Use available tools.
- (org-export-expand-macro macro info))
-
-
-;;;; Paragraph
-
-(defun org-e-odt-paragraph (paragraph contents info)
- "Transcode a PARAGRAPH element from Org to ODT.
-CONTENTS is the contents of the paragraph, as a string. INFO is
-the plist used as a communication channel."
- (let* ((parent (org-export-get-parent paragraph))
- (parent-type (org-element-type parent))
- (style (case parent-type
- (quote-block "Quotations")
- (center-block "OrgCenter")
- (footnote-definition "Footnote")
- (t "Text_20_body"))))
- ;; If this paragraph is a leading paragraph in a non-descriptive
- ;; item and the item has a checkbox, splice the checkbox and
- ;; paragraph contents together.
- (when (and (eq (org-element-type parent) 'item)
- (not (eq (org-element-property :type
- (org-export-get-parent parent))
- 'descriptive))
- (eq paragraph (car (org-element-contents parent))))
- (setq contents (concat (org-e-odt--checkbox parent) contents)))
- (assert style)
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>" style contents)))
-
-
-;;;; Plain List
-
-(defun org-e-odt-plain-list (plain-list contents info)
- "Transcode a PLAIN-LIST element from Org to ODT.
-CONTENTS is the contents of the list. INFO is a plist holding
-contextual information."
- (let* ((type (org-element-property :type plain-list))
- (continue-numbering nil))
- (assert (member type '(ordered unordered descriptive)))
- (org-e-odt--wrap-label
- plain-list
- (format "\n<text:list text:style-name=\"%s\" %s>\n%s</text:list>"
- (assoc-default type '((ordered . "OrgNumberedList")
- (unordered . "OrgBulletedList")
- (descriptive . "OrgDescriptionList")))
- ;; If top-level list, re-start numbering. Otherwise,
- ;; continue numbering.
- (format "text:continue-numbering=\"%s\""
- (let* ((parent (org-export-get-parent plain-list)))
- (if (and parent (eq (org-element-type parent) 'item))
- "true" "false")))
- contents))))
-
-;;;; Plain Text
-
-(defun org-e-odt-fill-tabs-and-spaces (line)
- (replace-regexp-in-string
- "\\([\t]\\|\\([ ]+\\)\\)"
- (lambda (s)
- (cond
- ((string= s "\t") "<text:tab/>")
- (t (let ((n (length s)))
- (cond
- ((= n 1) " ")
- ((> n 1) (concat " " (format "<text:s text:c=\"%d\"/>" (1- n))))
- (t ""))))))
- line))
-
-(defun org-e-odt-encode-plain-text (text &optional no-whitespace-filling)
- (mapc
- (lambda (pair)
- (setq text (replace-regexp-in-string (car pair) (cdr pair) text t t)))
- '(("&" . "&amp;") ("<" . "&lt;") (">" . "&gt;")))
- (if no-whitespace-filling text
- (org-e-odt-fill-tabs-and-spaces text)))
-
-(defun org-e-odt--quotation-marks (text info)
- "Export quotation marks depending on language conventions.
-TEXT is a string containing quotation marks to be replaced. INFO
-is a plist used as a communication channel."
- (mapc (lambda(l)
- (let ((start 0))
- (while (setq start (string-match (car l) text start))
- (let ((new-quote (concat (match-string 1 text) (cdr l))))
- (setq text (replace-match new-quote t t text))))))
- (cdr (or (assoc (plist-get info :language) org-e-odt-quotes)
- ;; Falls back on English.
- (assoc "en" org-e-odt-quotes))))
- text)
-
-(defun org-e-odt-plain-text (text info)
- "Transcode a TEXT string from Org to ODT.
-TEXT is the string to transcode. INFO is a plist holding
-contextual information."
- ;; Protect &, < and >.
- (setq text (org-e-odt-encode-plain-text text t))
- ;; Handle quotation marks
- (setq text (org-e-odt--quotation-marks text info))
- ;; Convert special strings.
- (when (plist-get info :with-special-strings)
- (mapc
- (lambda (pair)
- (setq text (replace-regexp-in-string (car pair) (cdr pair) text t nil)))
- org-e-odt-special-string-regexps))
- ;; Handle break preservation if required.
- (when (plist-get info :preserve-breaks)
- (setq text (replace-regexp-in-string
- "\\(\\\\\\\\\\)?[ \t]*\n" "<text:line-break/>\n" text t)))
- ;; Return value.
- text)
-
-
-;;;; Planning
-
-(defun org-e-odt-planning (planning contents info)
- "Transcode a PLANNING element from Org to ODT.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestampWrapper"
- (concat
- (let ((closed (org-element-property :closed planning)))
- (when closed
- (concat
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestampKeyword" org-closed-string)
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestamp" (org-translate-time closed)))))
- (let ((deadline (org-element-property :deadline planning)))
- (when deadline
- (concat
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestampKeyword" org-deadline-string)
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestamp" (org-translate-time deadline)))))
- (let ((scheduled (org-element-property :scheduled planning)))
- (when scheduled
- (concat
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestampKeyword" org-scheduled-string)
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestamp" (org-translate-time scheduled))))))))
-
-
-;;;; Property Drawer
-
-(defun org-e-odt-property-drawer (property-drawer contents info)
- "Transcode a PROPERTY-DRAWER element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- ;; The property drawer isn't exported but we want separating blank
- ;; lines nonetheless.
- "")
-
-
-;;;; Quote Block
-
-(defun org-e-odt-quote-block (quote-block contents info)
- "Transcode a QUOTE-BLOCK element from Org to ODT.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (org-e-odt--wrap-label quote-block contents))
-
-
-;;;; Quote Section
-
-(defun org-e-odt-quote-section (quote-section contents info)
- "Transcode a QUOTE-SECTION element from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((value (org-remove-indentation
- (org-element-property :value quote-section))))
- (when value (org-e-odt-do-format-code value))))
-
-
-;;;; Section
-
-
-(defun org-e-odt-format-section (text style &optional name)
- (let ((default-name (car (org-e-odt-add-automatic-style "Section"))))
- (format "\n<text:section text:style-name=\"%s\" %s>\n%s</text:section>"
- style
- (format "text:name=\"%s\"" (or name default-name))
- text)))
-
-
-(defun org-e-odt-section (section contents info) ; FIXME
- "Transcode a SECTION element from Org to ODT.
-CONTENTS holds the contents of the section. INFO is a plist
-holding contextual information."
- contents)
-
-;;;; Radio Target
-
-(defun org-e-odt-radio-target (radio-target text info)
- "Transcode a RADIO-TARGET object from Org to ODT.
-TEXT is the text of the target. INFO is a plist holding
-contextual information."
- (org-e-odt-format-target
- text (org-export-solidify-link-text
- (org-element-property :value radio-target))))
-
-
-;;;; Special Block
-
-(defun org-e-odt-special-block (special-block contents info)
- "Transcode a SPECIAL-BLOCK element from Org to ODT.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((type (downcase (org-element-property :type special-block)))
- (attributes (org-export-read-attribute :attr_odt special-block)))
- (org-e-odt--wrap-label
- special-block
- (cond
- ;; Annotation.
- ((string= type "annotation")
- (let ((author (or (plist-get attributes :author)
- (let ((author (plist-get info :author)))
- (and author (org-export-data author info)))))
- (date (or (plist-get attributes :date)
- (plist-get info :date))))
-
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Text_20_body"
- (format "<office:annotation>\n%s\n</office:annotation>"
- (concat
- (and author
- (format "<dc:creator>%s</dc:creator>" author))
- (and date
- (format "<dc:date>%s</dc:date>"
- (org-e-odt--date date)))
- contents)))))
- ;; Textbox.
- ((string= type "textbox")
- (let ((width (plist-get attributes :width))
- (height (plist-get attributes :height))
- (style (plist-get attributes :style))
- (extra (plist-get attributes :extra))
- (anchor (plist-get attributes :anchor)))
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Text_20_body" (org-e-odt--textbox contents width height
- style extra anchor))))
- (t contents)))))
-
-
-;;;; Src Block
-
-
-(defun org-e-odt-hfy-face-to-css (fn)
- "Create custom style for face FN.
-When FN is the default face, use it's foreground and background
-properties to create \"OrgSrcBlock\" paragraph style. Otherwise
-use it's color attribute to create a character style whose name
-is obtained from FN. Currently all attributes of FN other than
-color are ignored.
-
-The style name for a face FN is derived using the following
-operations on the face name in that order - de-dash, CamelCase
-and prefix with \"OrgSrc\". For example,
-`font-lock-function-name-face' is associated with
-\"OrgSrcFontLockFunctionNameFace\"."
- (let* ((css-list (hfy-face-to-style fn))
- (style-name ((lambda (fn)
- (concat "OrgSrc"
- (mapconcat
- 'capitalize (split-string
- (hfy-face-or-def-to-name fn) "-")
- ""))) fn))
- (color-val (cdr (assoc "color" css-list)))
- (background-color-val (cdr (assoc "background" css-list)))
- (style (and org-e-odt-create-custom-styles-for-srcblocks
- (cond
- ((eq fn 'default)
- (format org-e-odt-src-block-paragraph-format
- background-color-val color-val))
- (t
- (format
- "
-<style:style style:name=\"%s\" style:family=\"text\">
- <style:text-properties fo:color=\"%s\"/>
- </style:style>" style-name color-val))))))
- (cons style-name style)))
-
-(defun org-e-odt-htmlfontify-string (line)
- (let* ((hfy-html-quote-regex "\\([<\"&> ]\\)")
- (hfy-html-quote-map '(("\"" "&quot;")
- ("<" "&lt;")
- ("&" "&amp;")
- (">" "&gt;")
- (" " "<text:s/>")
- (" " "<text:tab/>")))
- (hfy-face-to-css 'org-e-odt-hfy-face-to-css)
- (hfy-optimisations-1 (copy-seq hfy-optimisations))
- (hfy-optimisations (add-to-list 'hfy-optimisations-1
- 'body-text-only))
- (hfy-begin-span-handler
- (lambda (style text-block text-id text-begins-block-p)
- (insert (format "<text:span text:style-name=\"%s\">" style))))
- (hfy-end-span-handler (lambda nil (insert "</text:span>"))))
- (with-no-warnings (htmlfontify-string line))))
-
-(defun org-e-odt-do-format-code
- (code &optional lang refs retain-labels num-start)
- (let* ((lang (or (assoc-default lang org-src-lang-modes) lang))
- (lang-mode (and lang (intern (format "%s-mode" lang))))
- (code-lines (org-split-string code "\n"))
- (code-length (length code-lines))
- (use-htmlfontify-p (and (functionp lang-mode)
- org-e-odt-fontify-srcblocks
- (require 'htmlfontify nil t)
- (fboundp 'htmlfontify-string)))
- (code (if (not use-htmlfontify-p) code
- (with-temp-buffer
- (insert code)
- (funcall lang-mode)
- (font-lock-fontify-buffer)
- (buffer-string))))
- (fontifier (if use-htmlfontify-p 'org-e-odt-htmlfontify-string
- 'org-e-odt-encode-plain-text))
- (par-style (if use-htmlfontify-p "OrgSrcBlock"
- "OrgFixedWidthBlock"))
- (i 0))
- (assert (= code-length (length (org-split-string code "\n"))))
- (setq code
- (org-export-format-code
- code
- (lambda (loc line-num ref)
- (setq par-style
- (concat par-style (and (= (incf i) code-length) "LastLine")))
-
- (setq loc (concat loc (and ref retain-labels (format " (%s)" ref))))
- (setq loc (funcall fontifier loc))
- (when ref
- (setq loc (org-e-odt-format-target loc (concat "coderef-" ref))))
- (assert par-style)
- (setq loc (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- par-style loc))
- (if (not line-num) loc
- (format "\n<text:list-item>%s\n</text:list-item>" loc)))
- num-start refs))
- (cond
- ((not num-start) code)
- ((= num-start 0)
- (format
- "\n<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>%s</text:list>"
- " text:continue-numbering=\"false\"" code))
- (t
- (format
- "\n<text:list text:style-name=\"OrgSrcBlockNumberedLine\"%s>%s</text:list>"
- " text:continue-numbering=\"true\"" code)))))
-
-(defun org-e-odt-format-code (element info)
- (let* ((lang (org-element-property :language element))
- ;; Extract code and references.
- (code-info (org-export-unravel-code element))
- (code (car code-info))
- (refs (cdr code-info))
- ;; Does the src block contain labels?
- (retain-labels (org-element-property :retain-labels element))
- ;; Does it have line numbers?
- (num-start (case (org-element-property :number-lines element)
- (continued (org-export-get-loc element info))
- (new 0))))
- (org-e-odt-do-format-code code lang refs retain-labels num-start)))
-
-(defun org-e-odt-src-block (src-block contents info)
- "Transcode a SRC-BLOCK element from Org to ODT.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((lang (org-element-property :language src-block))
- (caption (org-element-property :caption src-block))
- (short-caption (and (cdr caption)
- (org-export-data (cdr caption) info)))
- (caption (and (car caption) (org-export-data (car caption) info)))
- (label (org-element-property :name src-block))
- (attributes (org-export-read-attribute :attr_odt src-block)))
- ;; FIXME: Handle caption
- ;; caption-str (when caption)
- ;; (main (org-export-data (car caption) info))
- ;; (secondary (org-export-data (cdr caption) info))
- ;; (caption-str (org-e-odt--caption/label-string caption label info))
- (let* ((captions (org-e-odt-format-label src-block info 'definition))
- (caption (car captions)) (short-caption (cdr captions)))
- (concat
- (and caption
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Listing" caption))
- (let ((--src-block (org-e-odt-format-code src-block info)))
- (if (not (plist-get attributes :textbox)) --src-block
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Text_20_body"
- (org-e-odt--textbox --src-block nil nil nil))))))))
-
-
-;;;; Statistics Cookie
-
-(defun org-e-odt-statistics-cookie (statistics-cookie contents info)
- "Transcode a STATISTICS-COOKIE object from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((cookie-value (org-element-property :value statistics-cookie)))
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgCode" cookie-value)))
-
-
-;;;; Strike-Through
-
-(defun org-e-odt-strike-through (strike-through contents info)
- "Transcode STRIKE-THROUGH from Org to ODT.
-CONTENTS is the text with strike-through markup. INFO is a plist
-holding contextual information."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "Strikethrough" contents))
-
-
-;;;; Subscript
-
-(defun org-e-odt-subscript (subscript contents info)
- "Transcode a SUBSCRIPT object from Org to ODT.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgSubscript" contents))
-
-
-;;;; Superscript
-
-(defun org-e-odt-superscript (superscript contents info)
- "Transcode a SUPERSCRIPT object from Org to ODT.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgSuperscript" contents))
-
-
-;;;; Table Cell
-
-(defun org-e-odt-table-style-spec (element info)
- (let* ((table (org-export-get-parent-table element))
- (table-attributes (org-export-read-attribute :attr_odt table))
- (table-style (plist-get table-attributes :style)))
- (assoc table-style org-e-odt-table-styles)))
-
-(defun org-e-odt-get-table-cell-styles (table-cell info)
- "Retrieve styles applicable to a table cell.
-R and C are (zero-based) row and column numbers of the table
-cell. STYLE-SPEC is an entry in `org-e-odt-table-styles'
-applicable to the current table. It is `nil' if the table is not
-associated with any style attributes.
-
-Return a cons of (TABLE-CELL-STYLE-NAME . PARAGRAPH-STYLE-NAME).
-
-When STYLE-SPEC is nil, style the table cell the conventional way
-- choose cell borders based on row and column groupings and
-choose paragraph alignment based on `org-col-cookies' text
-property. See also
-`org-e-odt-get-paragraph-style-cookie-for-table-cell'.
-
-When STYLE-SPEC is non-nil, ignore the above cookie and return
-styles congruent with the ODF-1.2 specification."
- (let* ((table-cell-address (org-export-table-cell-address table-cell info))
- (r (car table-cell-address)) (c (cdr table-cell-address))
- (style-spec (org-e-odt-table-style-spec table-cell info))
- (table-dimensions (org-export-table-dimensions
- (org-export-get-parent-table table-cell)
- info)))
- (when style-spec
- ;; LibreOffice - particularly the Writer - honors neither table
- ;; templates nor custom table-cell styles. Inorder to retain
- ;; inter-operability with LibreOffice, only automatic styles are
- ;; used for styling of table-cells. The current implementation is
- ;; congruent with ODF-1.2 specification and hence is
- ;; future-compatible.
-
- ;; Additional Note: LibreOffice's AutoFormat facility for tables -
- ;; which recognizes as many as 16 different cell types - is much
- ;; richer. Unfortunately it is NOT amenable to easy configuration
- ;; by hand.
- (let* ((template-name (nth 1 style-spec))
- (cell-style-selectors (nth 2 style-spec))
- (cell-type
- (cond
- ((and (cdr (assoc 'use-first-column-styles cell-style-selectors))
- (= c 0)) "FirstColumn")
- ((and (cdr (assoc 'use-last-column-styles cell-style-selectors))
- (= (1+ c) (cdr table-dimensions)))
- "LastColumn")
- ((and (cdr (assoc 'use-first-row-styles cell-style-selectors))
- (= r 0)) "FirstRow")
- ((and (cdr (assoc 'use-last-row-styles cell-style-selectors))
- (= (1+ r) (car table-dimensions)))
- "LastRow")
- ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
- (= (% r 2) 1)) "EvenRow")
- ((and (cdr (assoc 'use-banding-rows-styles cell-style-selectors))
- (= (% r 2) 0)) "OddRow")
- ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
- (= (% c 2) 1)) "EvenColumn")
- ((and (cdr (assoc 'use-banding-columns-styles cell-style-selectors))
- (= (% c 2) 0)) "OddColumn")
- (t ""))))
- (concat template-name cell-type)))))
-
-(defun org-e-odt-table-cell (table-cell contents info)
- "Transcode a TABLE-CELL element from Org to ODT.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (let* ((table-cell-address (org-export-table-cell-address table-cell info))
- (r (car table-cell-address))
- (c (cdr table-cell-address))
- (horiz-span (or (org-export-table-cell-width table-cell info) 0))
- (table-row (org-export-get-parent table-cell))
- (custom-style-prefix (org-e-odt-get-table-cell-styles
- table-cell info))
- (paragraph-style
- (or
- (and custom-style-prefix
- (format "%sTableParagraph" custom-style-prefix))
- (concat
- (cond
- ((and (= 1 (org-export-table-row-group table-row info))
- (org-export-table-has-header-p
- (org-export-get-parent-table table-row) info))
- "OrgTableHeading")
- ((let* ((table (org-export-get-parent-table table-cell))
- (table-attrs (org-export-read-attribute :attr_odt table))
- (table-header-columns (plist-get table-attrs
- :header-columns)))
- (<= c (cond ((wholenump table-header-columns)
- (- table-header-columns 1))
- (table-header-columns 0)
- (t -1))))
- "OrgTableHeading")
- (t "OrgTableContents"))
- (capitalize (symbol-name (org-export-table-cell-alignment
- table-cell info))))))
- (cell-style-name
- (or
- (and custom-style-prefix (format "%sTableCell"
- custom-style-prefix))
- (concat
- "OrgTblCell"
- (when (or (org-export-table-row-starts-rowgroup-p table-row info)
- (zerop r)) "T")
- (when (org-export-table-row-ends-rowgroup-p table-row info) "B")
- (when (and (org-export-table-cell-starts-colgroup-p table-cell info)
- (not (zerop c)) ) "L"))))
- (cell-attributes
- (concat
- (format " table:style-name=\"%s\"" cell-style-name)
- (and (> horiz-span 0)
- (format " table:number-columns-spanned=\"%d\""
- (1+ horiz-span))))))
- (unless contents (setq contents ""))
- (concat
- (assert paragraph-style)
- (format "\n<table:table-cell%s>\n%s\n</table:table-cell>"
- cell-attributes
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- paragraph-style contents))
- (let (s)
- (dotimes (i horiz-span s)
- (setq s (concat s "\n<table:covered-table-cell/>"))))
- "\n")))
-
-
-;;;; Table Row
-
-(defun org-e-odt-table-row (table-row contents info)
- "Transcode a TABLE-ROW element from Org to ODT.
-CONTENTS is the contents of the row. INFO is a plist used as a
-communication channel."
- ;; Rules are ignored since table separators are deduced from
- ;; borders of the current row.
- (when (eq (org-element-property :type table-row) 'standard)
- (let* ((rowgroup-tags
- (if (and (= 1 (org-export-table-row-group table-row info))
- (org-export-table-has-header-p
- (org-export-get-parent-table table-row) info))
- ;; If the row belongs to the first rowgroup and the
- ;; table has more than one row groups, then this row
- ;; belongs to the header row group.
- '("\n<table:table-header-rows>" . "\n</table:table-header-rows>")
- ;; Otherwise, it belongs to non-header row group.
- '("\n<table:table-rows>" . "\n</table:table-rows>"))))
- (concat
- ;; Does this row begin a rowgroup?
- (when (org-export-table-row-starts-rowgroup-p table-row info)
- (car rowgroup-tags))
- ;; Actual table row
- (format "\n<table:table-row>\n%s\n</table:table-row>" contents)
- ;; Does this row end a rowgroup?
- (when (org-export-table-row-ends-rowgroup-p table-row info)
- (cdr rowgroup-tags))))))
-
-
-;;;; Table
-
-(defun org-e-odt-table-first-row-data-cells (table info)
- (let ((table-row
- (org-element-map
- table 'table-row
- (lambda (row)
- (unless (eq (org-element-property :type row) 'rule) row))
- info 'first-match))
- (special-column-p (org-export-table-has-special-column-p table)))
- (if (not special-column-p) (org-element-contents table-row)
- (cdr (org-element-contents table-row)))))
-
-(defun org-e-odt--table (table contents info)
- "Transcode a TABLE element from Org to ODT.
-CONTENTS is the contents of the table. INFO is a plist holding
-contextual information."
- (case (org-element-property :type table)
- ;; Case 1: table.el doesn't support export to OD format. Strip
- ;; such tables from export.
- (table.el
- (prog1 nil
- (message
- (concat
- "(org-e-odt): Found table.el-type table in the source Org file."
- " table.el doesn't support export to ODT format."
- " Stripping the table from export."))))
- ;; Case 2: Native Org tables.
- (otherwise
- (let* ((captions (org-e-odt-format-label table info 'definition))
- (caption (car captions)) (short-caption (cdr captions))
- (attributes (org-export-read-attribute :attr_odt table))
- (custom-table-style (nth 1 (org-e-odt-table-style-spec table info)))
- (table-column-specs
- (function
- (lambda (table info)
- (let* ((table-style (or custom-table-style "OrgTable"))
- (column-style (format "%sColumn" table-style)))
- (mapconcat
- (lambda (table-cell)
- (let ((width (1+ (or (org-export-table-cell-width
- table-cell info) 0)))
- (s (format
- "\n<table:table-column table:style-name=\"%s\"/>"
- column-style))
- out)
- (dotimes (i width out) (setq out (concat s out)))))
- (org-e-odt-table-first-row-data-cells table info) "\n"))))))
- (concat
- ;; caption.
- (when caption
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "Table" caption))
- ;; begin table.
- (let* ((automatic-name
- (org-e-odt-add-automatic-style "Table" attributes)))
- (format
- "\n<table:table table:name=\"%s\" table:style-name=\"%s\">"
- (or short-caption (car automatic-name))
- (or custom-table-style (cdr automatic-name) "OrgTable")))
- ;; column specification.
- (funcall table-column-specs table info)
- ;; actual contents.
- "\n" contents
- ;; end table.
- "</table:table>")))))
-
-(defun org-e-odt-table (table contents info)
- "Transcode a TABLE element from Org to ODT.
-CONTENTS is the contents of the table. INFO is a plist holding
-contextual information."
- (let* ((--get-previous-elements
- (function
- (lambda (blob info)
- (let ((parent (org-export-get-parent blob)))
- (cdr (member blob (reverse (org-element-contents parent))))))))
- (--element-preceded-by-table-p
- (function
- (lambda (element info)
- (loop for el in (funcall --get-previous-elements element info)
- thereis (eq (org-element-type el) 'table)))))
- (--walk-list-genealogy-and-collect-tags
- (function
- (lambda (table info)
- (let* ((genealogy (org-export-get-genealogy table))
- (list-genealogy
- (when (eq (org-element-type (car genealogy)) 'item)
- (loop for el in genealogy
- when (member (org-element-type el)
- '(item plain-list))
- collect el))))
- (loop for el in list-genealogy
- with parent-list collect
- (case (org-element-type el)
- (plain-list
- (setq parent-list el)
- `("</text:list>"
- . ,(let ((type (org-element-property :type el)))
- (format
- "<text:list text:style-name=\"%s\" %s>"
- (assoc-default
- type '((ordered . "OrgNumberedList")
- (unordered . "OrgBulletedList")
- (descriptive . "OrgDescriptionList")))
- "text:continue-numbering=\"true\""))))
- (item
- (cond
- ((not parent-list)
- (if (funcall --element-preceded-by-table-p table info)
- '("</text:list-header>" . "<text:list-header>")
- '("</text:list-item>" . "<text:list-header>")))
- ((funcall --element-preceded-by-table-p
- parent-list info)
- '("</text:list-header>" . "<text:list-header>"))
- (t '("</text:list-item>" . "<text:list-item>"))))))))))
- (close-open-tags (funcall --walk-list-genealogy-and-collect-tags
- table info)))
- ;; OpenDocument schema does not permit table to occur within a
- ;; list item. So, to typeset an indented table, we make use of
- ;; list continuations.
- (concat "\n"
- ;; Discontinue the list.
- (mapconcat 'car close-open-tags "\n")
- ;; Put the table in an indented section.
- (let* ((table (org-e-odt--table table contents info))
- (level (/ (length (mapcar 'car close-open-tags)) 2))
- (style (format "OrgIndentedSection-Level-%d" level)))
- (when table (org-e-odt-format-section table style)))
- ;; Continue the list.
- (mapconcat 'cdr (nreverse close-open-tags) "\n"))))
-
-
-;;;; Target
-
-(defun org-e-odt-target (target contents info)
- "Transcode a TARGET object from Org to ODT.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (org-e-odt-format-target
- "" (org-export-solidify-link-text (org-element-property :value target))))
-
-
-;;;; Timestamp
-
-(defun org-e-odt-timestamp (timestamp contents info)
- "Transcode a TIMESTAMP object from Org to ODT.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (let ((timestamp-1 (org-element-property :value timestamp))
- (timestamp-2 (org-element-property :range-end timestamp)))
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestampWrapper"
- (concat
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestamp" (org-translate-time timestamp-1))
- (and timestamp-2
- "&#x2013;"
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgTimestamp" (org-translate-time timestamp-2)))))))
-
-
-;;;; Underline
-
-(defun org-e-odt-underline (underline contents info)
- "Transcode UNDERLINE from Org to ODT.
-CONTENTS is the text with underline markup. INFO is a plist
-holding contextual information."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "Underline" contents))
-
-
-;;;; Verbatim
-
-(defun org-e-odt-verbatim (verbatim contents info)
- "Transcode a VERBATIM object from Org to ODT.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (format "<text:span text:style-name=\"%s\">%s</text:span>"
- "OrgCode" (org-element-property :value verbatim)))
-
-
-;;;; Verse Block
-
-(defun org-e-odt-verse-block (verse-block contents info)
- "Transcode a VERSE-BLOCK element from Org to ODT.
-CONTENTS is verse block contents. INFO is a plist holding
-contextual information."
- ;; Add line breaks to each line of verse.
- (setq contents (replace-regexp-in-string
- "\\(<text:line-break/>\\)?[ \t]*\n"
- "<text:line-break/>" contents))
- ;; Replace tabs and spaces.
- (setq contents (org-e-odt-fill-tabs-and-spaces contents))
- ;; Surround it in a verse environment.
- (org-e-odt--wrap-label
- verse-block
- (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
- "OrgVerse" contents)))
-
-
-
-
-
-;;; Interactive functions
-
-(defun org-e-odt-create-manifest-file-entry (&rest args)
- (push args org-e-odt-manifest-file-entries))
-
-(defun org-e-odt-write-manifest-file ()
- (make-directory (concat org-e-odt-zip-dir "META-INF"))
- (let ((manifest-file (concat org-e-odt-zip-dir "META-INF/manifest.xml")))
- (with-current-buffer
- (let ((nxml-auto-insert-xml-declaration-flag nil))
- (find-file-noselect manifest-file t))
- (insert
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
- <manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\" manifest:version=\"1.2\">\n")
- (mapc
- (lambda (file-entry)
- (let* ((version (nth 2 file-entry))
- (extra (if (not version) ""
- (format " manifest:version=\"%s\"" version))))
- (insert
- (format org-e-odt-manifest-file-entry-tag
- (nth 0 file-entry) (nth 1 file-entry) extra))))
- org-e-odt-manifest-file-entries)
- (insert "\n</manifest:manifest>"))))
-
-(defmacro org-e-odt--export-wrap (out-file &rest body)
- `(let* ((--out-file ,out-file)
- (out-file-type (file-name-extension --out-file))
- (org-e-odt-xml-files '("META-INF/manifest.xml" "content.xml"
- "meta.xml" "styles.xml"))
- ;; Initialize workarea. All files that end up in the
- ;; exported get created here.
- (org-e-odt-zip-dir (file-name-as-directory
- (make-temp-file (format "%s-" out-file-type) t)))
- (org-e-odt-manifest-file-entries nil)
- (--cleanup-xml-buffers
- (function
- (lambda nil
- ;; Kill all XML buffers.
- (mapc (lambda (file)
- (let ((buf (get-file-buffer
- (concat org-e-odt-zip-dir file))))
- (when buf
- (set-buffer-modified-p nil)
- (kill-buffer buf))))
- org-e-odt-xml-files)
- ;; Delete temporary directory and also other embedded
- ;; files that get copied there.
- (delete-directory org-e-odt-zip-dir t)))))
- (org-condition-case-unless-debug
- err
- (progn
- (unless (executable-find "zip")
- ;; Not at all OSes ship with zip by default
- (error "Executable \"zip\" needed for creating OpenDocument files"))
- ;; Do export. This creates a bunch of xml files ready to be
- ;; saved and zipped.
- (progn ,@body)
- ;; Create a manifest entry for content.xml.
- (org-e-odt-create-manifest-file-entry "text/xml" "content.xml")
-
- ;; Write mimetype file
- (let* ((mimetypes
- '(("odt" . "application/vnd.oasis.opendocument.text")
- ("odf" . "application/vnd.oasis.opendocument.formula")))
- (mimetype (cdr (assoc-string out-file-type mimetypes t))))
- (unless mimetype
- (error "Unknown OpenDocument backend %S" out-file-type))
- (write-region mimetype nil (concat org-e-odt-zip-dir "mimetype"))
- (org-e-odt-create-manifest-file-entry mimetype "/" "1.2"))
- ;; Write out the manifest entries before zipping
- (org-e-odt-write-manifest-file)
- ;; Save all XML files.
- (mapc (lambda (file)
- (let ((buf (get-file-buffer (concat org-e-odt-zip-dir file))))
- (when buf
- (with-current-buffer buf
- ;; Prettify output if needed.
- (when org-e-odt-prettify-xml
- (indent-region (point-min) (point-max)))
- (save-buffer 0)))))
- org-e-odt-xml-files)
- ;; Run zip.
- (let* ((target --out-file)
- (target-name (file-name-nondirectory target))
- (target-dir (file-name-directory target))
- (cmds `(("zip" "-mX0" ,target-name "mimetype")
- ("zip" "-rmTq" ,target-name "."))))
- ;; If a file with same name as the desired output file
- ;; exists, remove it.
- (when (file-exists-p target)
- (delete-file target))
- ;; Zip up the xml files.
- (let ((coding-system-for-write 'no-conversion) exitcode err-string)
- (message "Creating ODT file...")
- ;; Switch temporarily to content.xml. This way Zip
- ;; process will inherit `org-e-odt-zip-dir' as the current
- ;; directory.
- (with-current-buffer
- (find-file-noselect (concat org-e-odt-zip-dir "content.xml") t)
- (mapc
- (lambda (cmd)
- (message "Running %s" (mapconcat 'identity cmd " "))
- (setq err-string
- (with-output-to-string
- (setq exitcode
- (apply 'call-process (car cmd)
- nil standard-output nil (cdr cmd)))))
- (or (zerop exitcode)
- (error (concat "Unable to create OpenDocument file."
- (format " Zip failed with error (%s)"
- err-string)))))
- cmds)
- ;; Zip file is now in the rightful place.
- (rename-file target-name target)))
- (message "Created %s" target)
- ;; Cleanup work directory and work files.
- (funcall --cleanup-xml-buffers)
- ;; Open the OpenDocument file in archive-mode for
- ;; examination.
- (find-file-noselect target t)
- ;; Return exported file.
- (cond
- ;; Case 1: Conversion desired on exported file. Run the
- ;; converter on the OpenDocument file. Return the
- ;; converted file.
- (org-e-odt-preferred-output-format
- (or (org-e-odt-convert target org-e-odt-preferred-output-format)
- target))
- ;; Case 2: No further conversion. Return exported
- ;; OpenDocument file.
- (t target))))
- ((quit error)
- ;; Cleanup work directory and work files.
- (funcall --cleanup-xml-buffers)
- (message "OpenDocument export failed: %s"
- (error-message-string err))))))
-
-
-
-;;;###autoload
-(defun org-e-odt-export-as-odf (latex-frag &optional odf-file)
- "Export LATEX-FRAG as OpenDocument formula file ODF-FILE.
-Use `org-create-math-formula' to convert LATEX-FRAG first to
-MathML. When invoked as an interactive command, use
-`org-latex-regexps' to infer LATEX-FRAG from currently active
-region. If no LaTeX fragments are found, prompt for it. Push
-MathML source to kill ring, if `org-export-copy-to-kill-ring' is
-non-nil."
- (interactive
- `(,(let (frag)
- (setq frag (and (setq frag (and (region-active-p)
- (buffer-substring (region-beginning)
- (region-end))))
- (loop for e in org-latex-regexps
- thereis (when (string-match (nth 1 e) frag)
- (match-string (nth 2 e) frag)))))
- (read-string "LaTeX Fragment: " frag nil frag))
- ,(let ((odf-filename (expand-file-name
- (concat
- (file-name-sans-extension
- (or (file-name-nondirectory buffer-file-name)))
- "." "odf")
- (file-name-directory buffer-file-name))))
- (read-file-name "ODF filename: " nil odf-filename nil
- (file-name-nondirectory odf-filename)))))
- (let ((filename (or odf-file
- (expand-file-name
- (concat
- (file-name-sans-extension
- (or (file-name-nondirectory buffer-file-name)))
- "." "odf")
- (file-name-directory buffer-file-name)))))
- (org-e-odt--export-wrap
- filename
- (let* ((buffer (progn
- (require 'nxml-mode)
- (let ((nxml-auto-insert-xml-declaration-flag nil))
- (find-file-noselect (concat org-e-odt-zip-dir
- "content.xml") t))))
- (coding-system-for-write 'utf-8)
- (save-buffer-coding-system 'utf-8))
- (set-buffer buffer)
- (set-buffer-file-coding-system coding-system-for-write)
- (let ((mathml (org-create-math-formula latex-frag)))
- (unless mathml (error "No Math formula created"))
- (insert mathml)
- ;; Add MathML to kill ring, if needed.
- (when org-export-copy-to-kill-ring
- (org-kill-new (buffer-string))))))))
-
-;;;###autoload
-(defun org-e-odt-export-as-odf-and-open ()
- "Export LaTeX fragment as OpenDocument formula and immediately open it.
-Use `org-e-odt-export-as-odf' to read LaTeX fragment and OpenDocument
-formula file."
- (interactive)
- (org-open-file (call-interactively 'org-e-odt-export-as-odf)))
-
-;;;###autoload
-(defun org-e-odt-export-to-odt
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to a HTML file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (org-e-odt--export-wrap
- (org-export-output-file-name ".odt" subtreep pub-dir)
- (let* ((org-e-odt-embedded-images-count 0)
- (org-e-odt-embedded-formulas-count 0)
- (org-e-odt-automatic-styles nil)
- (org-e-odt-object-counters nil)
- ;; Let `htmlfontify' know that we are interested in collecting
- ;; styles.
- (hfy-user-sheet-assoc nil))
- ;; Initialize content.xml and kick-off the export process.
- (let ((out-buf (progn
- (require 'nxml-mode)
- (let ((nxml-auto-insert-xml-declaration-flag nil))
- (find-file-noselect
- (concat org-e-odt-zip-dir "content.xml") t)))))
- (org-export-to-buffer 'e-odt out-buf subtreep visible-only body-only)))))
-
-
-
-
-(defun org-e-odt-reachable-p (in-fmt out-fmt)
- "Return non-nil if IN-FMT can be converted to OUT-FMT."
- (catch 'done
- (let ((reachable-formats (org-e-odt-do-reachable-formats in-fmt)))
- (dolist (e reachable-formats)
- (let ((out-fmt-spec (assoc out-fmt (cdr e))))
- (when out-fmt-spec
- (throw 'done (cons (car e) out-fmt-spec))))))))
-
-(defun org-e-odt-do-convert (in-file out-fmt &optional prefix-arg)
- "Workhorse routine for `org-e-odt-convert'."
- (require 'browse-url)
- (let* ((in-file (expand-file-name (or in-file buffer-file-name)))
- (dummy (or (file-readable-p in-file)
- (error "Cannot read %s" in-file)))
- (in-fmt (file-name-extension in-file))
- (out-fmt (or out-fmt (error "Output format unspecified")))
- (how (or (org-e-odt-reachable-p in-fmt out-fmt)
- (error "Cannot convert from %s format to %s format?"
- in-fmt out-fmt)))
- (convert-process (car how))
- (out-file (concat (file-name-sans-extension in-file) "."
- (nth 1 (or (cdr how) out-fmt))))
- (extra-options (or (nth 2 (cdr how)) ""))
- (out-dir (file-name-directory in-file))
- (cmd (format-spec convert-process
- `((?i . ,(shell-quote-argument in-file))
- (?I . ,(browse-url-file-url in-file))
- (?f . ,out-fmt)
- (?o . ,out-file)
- (?O . ,(browse-url-file-url out-file))
- (?d . , (shell-quote-argument out-dir))
- (?D . ,(browse-url-file-url out-dir))
- (?x . ,extra-options)))))
- (when (file-exists-p out-file)
- (delete-file out-file))
-
- (message "Executing %s" cmd)
- (let ((cmd-output (shell-command-to-string cmd)))
- (message "%s" cmd-output))
-
- (cond
- ((file-exists-p out-file)
- (message "Exported to %s" out-file)
- (when prefix-arg
- (message "Opening %s..." out-file)
- (org-open-file out-file))
- out-file)
- (t
- (message "Export to %s failed" out-file)
- nil))))
-
-(defun org-e-odt-do-reachable-formats (in-fmt)
- "Return verbose info about formats to which IN-FMT can be converted.
-Return a list where each element is of the
-form (CONVERTER-PROCESS . OUTPUT-FMT-ALIST). See
-`org-e-odt-convert-processes' for CONVERTER-PROCESS and see
-`org-e-odt-convert-capabilities' for OUTPUT-FMT-ALIST."
- (let* ((converter
- (and org-e-odt-convert-process
- (cadr (assoc-string org-e-odt-convert-process
- org-e-odt-convert-processes t))))
- (capabilities
- (and org-e-odt-convert-process
- (cadr (assoc-string org-e-odt-convert-process
- org-e-odt-convert-processes t))
- org-e-odt-convert-capabilities))
- reachable-formats)
- (when converter
- (dolist (c capabilities)
- (when (member in-fmt (nth 1 c))
- (push (cons converter (nth 2 c)) reachable-formats))))
- reachable-formats))
-
-(defun org-e-odt-reachable-formats (in-fmt)
- "Return list of formats to which IN-FMT can be converted.
-The list of the form (OUTPUT-FMT-1 OUTPUT-FMT-2 ...)."
- (let (l)
- (mapc (lambda (e) (add-to-list 'l e))
- (apply 'append (mapcar
- (lambda (e) (mapcar 'car (cdr e)))
- (org-e-odt-do-reachable-formats in-fmt))))
- l))
-
-(defun org-e-odt-convert-read-params ()
- "Return IN-FILE and OUT-FMT params for `org-e-odt-do-convert'.
-This is a helper routine for interactive use."
- (let* ((input (if (featurep 'ido) 'ido-completing-read 'completing-read))
- (in-file (read-file-name "File to be converted: "
- nil buffer-file-name t))
- (in-fmt (file-name-extension in-file))
- (out-fmt-choices (org-e-odt-reachable-formats in-fmt))
- (out-fmt
- (or (and out-fmt-choices
- (funcall input "Output format: "
- out-fmt-choices nil nil nil))
- (error
- "No known converter or no known output formats for %s files"
- in-fmt))))
- (list in-file out-fmt)))
-
-;;;###autoload
-(defun org-e-odt-convert (&optional in-file out-fmt prefix-arg)
- "Convert IN-FILE to format OUT-FMT using a command line converter.
-IN-FILE is the file to be converted. If unspecified, it defaults
-to variable `buffer-file-name'. OUT-FMT is the desired output
-format. Use `org-e-odt-convert-process' as the converter.
-If PREFIX-ARG is non-nil then the newly converted file is opened
-using `org-open-file'."
- (interactive
- (append (org-e-odt-convert-read-params) current-prefix-arg))
- (org-e-odt-do-convert in-file out-fmt prefix-arg))
-
-;;; Library Initializations
-
-(mapc
- (lambda (desc)
- ;; Let Org open all OpenDocument files using system-registered app
- (add-to-list 'org-file-apps
- (cons (concat "\\." (car desc) "\\'") 'system))
- ;; Let Emacs open all OpenDocument files in archive mode
- (add-to-list 'auto-mode-alist
- (cons (concat "\\." (car desc) "\\'") 'archive-mode)))
- org-e-odt-file-extensions)
-
-(provide 'org-e-odt)
-
-;;; org-e-odt.el ends here
diff --git a/contrib/lisp/org-e-publish.el b/contrib/lisp/org-e-publish.el
deleted file mode 100644
index 894ee07..0000000
--- a/contrib/lisp/org-e-publish.el
+++ /dev/null
@@ -1,1200 +0,0 @@
-;;; org-e-publish.el --- publish related org-mode files as a website
-;; Copyright (C) 2006-2012 Free Software Foundation, Inc.
-
-;; Author: David O'Toole <dto@gnu.org>
-;; Maintainer: Carsten Dominik <carsten DOT dominik AT gmail DOT com>
-;; Keywords: hypermedia, outlines, wp
-
-;; This file is not part of GNU Emacs.
-;;
-;; GNU Emacs 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.
-
-;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This program allow configurable publishing of related sets of
-;; Org mode files as a complete website.
-;;
-;; org-e-publish.el can do the following:
-;;
-;; + Publish all one's Org files to HTML or PDF
-;; + Upload HTML, images, attachments and other files to a web server
-;; + Exclude selected private pages from publishing
-;; + Publish a clickable sitemap of pages
-;; + Manage local timestamps for publishing only changed files
-;; + Accept plugin functions to extend range of publishable content
-;;
-;; Documentation for publishing is in the manual.
-
-;;; Code:
-
-(eval-when-compile (require 'cl))
-(require 'format-spec)
-(require 'org-export)
-
-(declare-function org-e-latex-compile "org-e-latex" (texfile))
-
-
-
-;;; Variables
-(defvar org-e-publish-initial-buffer nil
- "The buffer `org-e-publish' has been called from.")
-
-(defvar org-e-publish-temp-files nil
- "Temporary list of files to be published.")
-
-;; Here, so you find the variable right before it's used the first time:
-(defvar org-e-publish-cache nil
- "This will cache timestamps and titles for files in publishing projects.
-Blocks could hash sha1 values here.")
-
-(defgroup org-e-publish nil
- "Options for publishing a set of Org-mode and related files."
- :tag "Org Publishing"
- :group 'org)
-
-(defcustom org-e-publish-project-alist nil
- "Association list to control publishing behavior.
-Each element of the alist is a publishing 'project.' The CAR of
-each element is a string, uniquely identifying the project. The
-CDR of each element is in one of the following forms:
-
-1. A well-formed property list with an even number of elements,
- alternating keys and values, specifying parameters for the
- publishing process.
-
- \(:property value :property value ... )
-
-2. A meta-project definition, specifying of a list of
- sub-projects:
-
- \(:components \(\"project-1\" \"project-2\" ...))
-
-When the CDR of an element of org-e-publish-project-alist is in
-this second form, the elements of the list after `:components'
-are taken to be components of the project, which group together
-files requiring different publishing options. When you publish
-such a project with \\[org-e-publish], the components all
-publish.
-
-When a property is given a value in
-`org-e-publish-project-alist', its setting overrides the value of
-the corresponding user variable \(if any) during publishing.
-However, options set within a file override everything.
-
-Most properties are optional, but some should always be set:
-
- `:base-directory'
-
- Directory containing publishing source files.
-
- `:base-extension'
-
- Extension \(without the dot!) of source files. This can be
- a regular expression. If not given, \"org\" will be used as
- default extension.
-
- `:publishing-directory'
-
- Directory \(possibly remote) where output files will be
- published.
-
-The `:exclude' property may be used to prevent certain files from
-being published. Its value may be a string or regexp matching
-file names you don't want to be published.
-
-The `:include' property may be used to include extra files. Its
-value may be a list of filenames to include. The filenames are
-considered relative to the base directory.
-
-When both `:include' and `:exclude' properties are given values,
-the exclusion step happens first.
-
-One special property controls which back-end function to use for
-publishing files in the project. This can be used to extend the
-set of file types publishable by `org-e-publish', as well as the
-set of output formats.
-
- `:publishing-function'
-
- Function to publish file. The default is
- `org-e-publish-org-to-ascii', but other values are possible.
- May also be a list of functions, in which case each function
- in the list is invoked in turn.
-
-Another property allows you to insert code that prepares
-a project for publishing. For example, you could call GNU Make
-on a certain makefile, to ensure published files are built up to
-date.
-
- `:preparation-function'
-
- Function to be called before publishing this project. This
- may also be a list of functions.
-
- `:completion-function'
-
- Function to be called after publishing this project. This
- may also be a list of functions.
-
-Some properties control details of the Org publishing process,
-and are equivalent to the corresponding user variables listed in
-the right column. Back-end specific properties may also be
-included. See the back-end documentation for more information.
-
- :author `user-full-name'
- :creator `org-export-creator-string'
- :email `user-mail-address'
- :exclude-tags `org-export-exclude-tags'
- :headline-levels `org-export-headline-levels'
- :language `org-export-default-language'
- :preserve-breaks `org-export-preserve-breaks'
- :section-numbers `org-export-with-section-numbers'
- :select-tags `org-export-select-tags'
- :time-stamp-file `org-export-time-stamp-file'
- :with-archived-trees `org-export-with-archived-trees'
- :with-author `org-export-with-author'
- :with-creator `org-export-with-creator'
- :with-drawers `org-export-with-drawers'
- :with-email `org-export-with-email'
- :with-emphasize `org-export-with-emphasize'
- :with-entities `org-export-with-entities'
- :with-fixed-width `org-export-with-fixed-width'
- :with-footnotes `org-export-with-footnotes'
- :with-priority `org-export-with-priority'
- :with-special-strings `org-export-with-special-strings'
- :with-sub-superscript `org-export-with-sub-superscripts'
- :with-toc `org-export-with-toc'
- :with-tables `org-export-with-tables'
- :with-tags `org-export-with-tags'
- :with-tasks `org-export-with-tasks'
- :with-timestamps `org-export-with-timestamps'
- :with-todo-keywords `org-export-with-todo-keywords'
-
-The following properties may be used to control publishing of
-a site-map of files or summary page for a given project.
-
- `:auto-sitemap'
-
- Whether to publish a site-map during
- `org-e-publish-current-project' or `org-e-publish-all'.
-
- `:sitemap-filename'
-
- Filename for output of sitemap. Defaults to \"sitemap.org\".
-
- `:sitemap-title'
-
- Title of site-map page. Defaults to name of file.
-
- `:sitemap-function'
-
- Plugin function to use for generation of site-map. Defaults to
- `org-e-publish-org-sitemap', which generates a plain list of
- links to all files in the project.
-
- `:sitemap-style'
-
- Can be `list' \(site-map is just an itemized list of the
- titles of the files involved) or `tree' \(the directory
- structure of the source files is reflected in the site-map).
- Defaults to `tree'.
-
- `:sitemap-sans-extension'
-
- Remove extension from site-map's file-names. Useful to have
- cool URIs \(see http://www.w3.org/Provider/Style/URI).
- Defaults to nil.
-
-If you create a site-map file, adjust the sorting like this:
-
- `:sitemap-sort-folders'
-
- Where folders should appear in the site-map. Set this to
- `first' \(default) or `last' to display folders first or
- last, respectively. Any other value will mix files and
- folders.
-
- `:sitemap-sort-files'
-
- The site map is normally sorted alphabetically. You can
- change this behaviour setting this to `anti-chronologically',
- `chronologically', or nil.
-
- `:sitemap-ignore-case'
-
- Should sorting be case-sensitive? Default nil.
-
-The following properties control the creation of a concept index.
-
- `:makeindex'
-
- Create a concept index.
-
-Other properties affecting publication.
-
- `:body-only'
-
- Set this to t to publish only the body of the documents."
- :group 'org-e-publish
- :type 'alist)
-
-(defcustom org-e-publish-use-timestamps-flag t
- "Non-nil means use timestamp checking to publish only changed files.
-When nil, do no timestamp checking and always publish all files."
- :group 'org-e-publish
- :type 'boolean)
-
-(defcustom org-e-publish-timestamp-directory
- (convert-standard-filename "~/.org-timestamps/")
- "Name of directory in which to store publishing timestamps."
- :group 'org-e-publish
- :type 'directory)
-
-(defcustom org-e-publish-list-skipped-files t
- "Non-nil means show message about files *not* published."
- :group 'org-e-publish
- :type 'boolean)
-
-(defcustom org-e-publish-sitemap-sort-files 'alphabetically
- "Method to sort files in site-maps.
-Possible values are `alphabetically', `chronologically',
-`anti-chronologically' and nil.
-
-If `alphabetically', files will be sorted alphabetically. If
-`chronologically', files will be sorted with older modification
-time first. If `anti-chronologically', files will be sorted with
-newer modification time first. nil won't sort files.
-
-You can overwrite this default per project in your
-`org-e-publish-project-alist', using `:sitemap-sort-files'."
- :group 'org-e-publish
- :type 'symbol)
-
-(defcustom org-e-publish-sitemap-sort-folders 'first
- "A symbol, denoting if folders are sorted first in sitemaps.
-Possible values are `first', `last', and nil.
-If `first', folders will be sorted before files.
-If `last', folders are sorted to the end after the files.
-Any other value will not mix files and folders.
-
-You can overwrite this default per project in your
-`org-e-publish-project-alist', using `:sitemap-sort-folders'."
- :group 'org-e-publish
- :type 'symbol)
-
-(defcustom org-e-publish-sitemap-sort-ignore-case nil
- "Non-nil when site-map sorting should ignore case.
-
-You can overwrite this default per project in your
-`org-e-publish-project-alist', using `:sitemap-ignore-case'."
- :group 'org-e-publish
- :type 'boolean)
-
-(defcustom org-e-publish-sitemap-date-format "%Y-%m-%d"
- "Format for `format-time-string' which is used to print a date
-in the sitemap."
- :group 'org-e-publish
- :type 'string)
-
-(defcustom org-e-publish-sitemap-file-entry-format "%t"
- "Format string for site-map file entry.
-You could use brackets to delimit on what part the link will be.
-
-%t is the title.
-%a is the author.
-%d is the date formatted using `org-e-publish-sitemap-date-format'."
- :group 'org-e-publish
- :type 'string)
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Timestamp-related functions
-
-(defun org-e-publish-timestamp-filename (filename &optional pub-dir pub-func)
- "Return path to timestamp file for filename FILENAME."
- (setq filename (concat filename "::" (or pub-dir "") "::"
- (format "%s" (or pub-func ""))))
- (concat "X" (if (fboundp 'sha1) (sha1 filename) (md5 filename))))
-
-(defun org-e-publish-needed-p
- (filename &optional pub-dir pub-func true-pub-dir base-dir)
- "Non-nil if FILENAME should be published in PUB-DIR using PUB-FUNC.
-TRUE-PUB-DIR is where the file will truly end up. Currently we
-are not using this - maybe it can eventually be used to check if
-the file is present at the target location, and how old it is.
-Right now we cannot do this, because we do not know under what
-file name the file will be stored - the publishing function can
-still decide about that independently."
- (let ((rtn (if (not org-e-publish-use-timestamps-flag) t
- (org-e-publish-cache-file-needs-publishing
- filename pub-dir pub-func base-dir))))
- (if rtn (message "Publishing file %s using `%s'" filename pub-func)
- (when org-e-publish-list-skipped-files
- (message "Skipping unmodified file %s" filename)))
- rtn))
-
-(defun org-e-publish-update-timestamp
- (filename &optional pub-dir pub-func base-dir)
- "Update publishing timestamp for file FILENAME.
-If there is no timestamp, create one."
- (let ((key (org-e-publish-timestamp-filename filename pub-dir pub-func))
- (stamp (org-e-publish-cache-ctime-of-src filename base-dir)))
- (org-e-publish-cache-set key stamp)))
-
-(defun org-e-publish-remove-all-timestamps ()
- "Remove all files in the timestamp directory."
- (let ((dir org-e-publish-timestamp-directory)
- files)
- (when (and (file-exists-p dir) (file-directory-p dir))
- (mapc 'delete-file (directory-files dir 'full "[^.]\\'"))
- (org-e-publish-reset-cache))))
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Getting project information out of `org-e-publish-project-alist'
-
-(defun org-e-publish-expand-projects (projects-alist)
- "Expand projects in PROJECTS-ALIST.
-This splices all the components into the list."
- (let ((rest projects-alist) rtn p components)
- (while (setq p (pop rest))
- (if (setq components (plist-get (cdr p) :components))
- (setq rest (append
- (mapcar (lambda (x) (assoc x org-e-publish-project-alist))
- components)
- rest))
- (push p rtn)))
- (nreverse (delete-dups (delq nil rtn)))))
-
-(defvar org-sitemap-sort-files)
-(defvar org-sitemap-sort-folders)
-(defvar org-sitemap-ignore-case)
-(defvar org-sitemap-requested)
-(defvar org-sitemap-date-format)
-(defvar org-sitemap-file-entry-format)
-(defun org-e-publish-compare-directory-files (a b)
- "Predicate for `sort', that sorts folders and files for sitemap."
- (let ((retval t))
- (when (or org-sitemap-sort-files org-sitemap-sort-folders)
- ;; First we sort files:
- (when org-sitemap-sort-files
- (case org-sitemap-sort-files
- (alphabetically
- (let* ((adir (file-directory-p a))
- (aorg (and (string-match "\\.org$" a) (not adir)))
- (bdir (file-directory-p b))
- (borg (and (string-match "\\.org$" b) (not bdir)))
- (A (if aorg (concat (file-name-directory a)
- (org-e-publish-find-title a)) a))
- (B (if borg (concat (file-name-directory b)
- (org-e-publish-find-title b)) b)))
- (setq retval (if org-sitemap-ignore-case
- (not (string-lessp (upcase B) (upcase A)))
- (not (string-lessp B A))))))
- ((anti-chronologically chronologically)
- (let* ((adate (org-e-publish-find-date a))
- (bdate (org-e-publish-find-date b))
- (A (+ (lsh (car adate) 16) (cadr adate)))
- (B (+ (lsh (car bdate) 16) (cadr bdate))))
- (setq retval
- (if (eq org-sitemap-sort-files 'chronologically) (<= A B)
- (>= A B)))))))
- ;; Directory-wise wins:
- (when org-sitemap-sort-folders
- ;; a is directory, b not:
- (cond
- ((and (file-directory-p a) (not (file-directory-p b)))
- (setq retval (equal org-sitemap-sort-folders 'first)))
- ;; a is not a directory, but b is:
- ((and (not (file-directory-p a)) (file-directory-p b))
- (setq retval (equal org-sitemap-sort-folders 'last))))))
- retval))
-
-(defun org-e-publish-get-base-files-1
- (base-dir &optional recurse match skip-file skip-dir)
- "Set `org-e-publish-temp-files' with files from BASE-DIR directory.
-If RECURSE is non-nil, check BASE-DIR recursively. If MATCH is
-non-nil, restrict this list to the files matching the regexp
-MATCH. If SKIP-FILE is non-nil, skip file matching the regexp
-SKIP-FILE. If SKIP-DIR is non-nil, don't check directories
-matching the regexp SKIP-DIR when recursing through BASE-DIR."
- (mapc (lambda (f)
- (let ((fd-p (file-directory-p f))
- (fnd (file-name-nondirectory f)))
- (if (and fd-p recurse
- (not (string-match "^\\.+$" fnd))
- (if skip-dir (not (string-match skip-dir fnd)) t))
- (org-e-publish-get-base-files-1
- f recurse match skip-file skip-dir)
- (unless (or fd-p ;; this is a directory
- (and skip-file (string-match skip-file fnd))
- (not (file-exists-p (file-truename f)))
- (not (string-match match fnd)))
-
- (pushnew f org-e-publish-temp-files)))))
- (if org-sitemap-requested
- (sort (directory-files base-dir t (unless recurse match))
- 'org-e-publish-compare-directory-files)
- (directory-files base-dir t (unless recurse match)))))
-
-(defun org-e-publish-get-base-files (project &optional exclude-regexp)
- "Return a list of all files in PROJECT.
-If EXCLUDE-REGEXP is set, this will be used to filter out
-matching filenames."
- (let* ((project-plist (cdr project))
- (base-dir (file-name-as-directory
- (plist-get project-plist :base-directory)))
- (include-list (plist-get project-plist :include))
- (recurse (plist-get project-plist :recursive))
- (extension (or (plist-get project-plist :base-extension) "org"))
- ;; sitemap-... variables are dynamically scoped for
- ;; org-e-publish-compare-directory-files:
- (org-sitemap-requested
- (plist-get project-plist :auto-sitemap))
- (sitemap-filename
- (or (plist-get project-plist :sitemap-filename) "sitemap.org"))
- (org-sitemap-sort-folders
- (if (plist-member project-plist :sitemap-sort-folders)
- (plist-get project-plist :sitemap-sort-folders)
- org-e-publish-sitemap-sort-folders))
- (org-sitemap-sort-files
- (cond ((plist-member project-plist :sitemap-sort-files)
- (plist-get project-plist :sitemap-sort-files))
- ;; For backward compatibility:
- ((plist-member project-plist :sitemap-alphabetically)
- (if (plist-get project-plist :sitemap-alphabetically)
- 'alphabetically nil))
- (t org-e-publish-sitemap-sort-files)))
- (org-sitemap-ignore-case
- (if (plist-member project-plist :sitemap-ignore-case)
- (plist-get project-plist :sitemap-ignore-case)
- org-e-publish-sitemap-sort-ignore-case))
- (match (if (eq extension 'any) "^[^\\.]"
- (concat "^[^\\.].*\\.\\(" extension "\\)$"))))
- ;; Make sure `org-sitemap-sort-folders' has an accepted value
- (unless (memq org-sitemap-sort-folders '(first last))
- (setq org-sitemap-sort-folders nil))
-
- (setq org-e-publish-temp-files nil)
- (if org-sitemap-requested
- (pushnew (expand-file-name (concat base-dir sitemap-filename))
- org-e-publish-temp-files))
- (org-e-publish-get-base-files-1 base-dir recurse match
- ;; FIXME distinguish exclude regexp
- ;; for skip-file and skip-dir?
- exclude-regexp exclude-regexp)
- (mapc (lambda (f)
- (pushnew
- (expand-file-name (concat base-dir f))
- org-e-publish-temp-files))
- include-list)
- org-e-publish-temp-files))
-
-(defun org-e-publish-get-project-from-filename (filename &optional up)
- "Return the project that FILENAME belongs to."
- (let* ((filename (expand-file-name filename))
- project-name)
-
- (catch 'p-found
- (dolist (prj org-e-publish-project-alist)
- (unless (plist-get (cdr prj) :components)
- ;; [[info:org:Selecting%20files]] shows how this is supposed to work:
- (let* ((r (plist-get (cdr prj) :recursive))
- (b (expand-file-name (file-name-as-directory
- (plist-get (cdr prj) :base-directory))))
- (x (or (plist-get (cdr prj) :base-extension) "org"))
- (e (plist-get (cdr prj) :exclude))
- (i (plist-get (cdr prj) :include))
- (xm (concat "^" b (if r ".+" "[^/]+") "\\.\\(" x "\\)$")))
- (when
- (or (and i
- (member filename
- (mapcar (lambda (file)
- (expand-file-name file b))
- i)))
- (and (not (and e (string-match e filename)))
- (string-match xm filename)))
- (setq project-name (car prj))
- (throw 'p-found project-name))))))
- (when up
- (dolist (prj org-e-publish-project-alist)
- (if (member project-name (plist-get (cdr prj) :components))
- (setq project-name (car prj)))))
- (assoc project-name org-e-publish-project-alist)))
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Pluggable publishing back-end functions
-
-(defun org-e-publish-org-to (backend filename extension plist pub-dir)
- "Publish an Org file to a specified back-end.
-
-BACKEND is a symbol representing the back-end used for
-transcoding. FILENAME is the filename of the Org file to be
-published. EXTENSION is the extension used for the output
-string, with the leading dot. PLIST is the property list for the
-given project. PUB-DIR is the publishing directory.
-
-Return output file name."
- (unless (file-exists-p pub-dir) (make-directory pub-dir t))
- ;; Check if a buffer visiting FILENAME is already open.
- (let* ((visitingp (find-buffer-visiting filename))
- (work-buffer (or visitingp (find-file-noselect filename))))
- (prog1 (with-current-buffer work-buffer
- (let ((output-file
- (org-export-output-file-name extension nil pub-dir))
- (body-p (plist-get plist :body-only)))
- (org-export-to-file
- backend output-file nil nil body-p
- ;; Install `org-e-publish-collect-index' in parse tree
- ;; filters. It isn't dependent on `:makeindex', since
- ;; we want to keep it up-to-date in cache anyway.
- (org-combine-plists
- plist `(:filter-parse-tree
- (org-e-publish-collect-index
- ,@(plist-get plist :filter-parse-tree)))))))
- ;; Remove opened buffer in the process.
- (unless visitingp (kill-buffer work-buffer)))))
-
-(defvar project-plist)
-(defun org-e-publish-org-to-latex (plist filename pub-dir)
- "Publish an Org file to LaTeX.
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (org-e-publish-org-to 'e-latex filename ".tex" plist pub-dir))
-
-(defun org-e-publish-org-to-pdf (plist filename pub-dir)
- "Publish an Org file to PDF \(via LaTeX).
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (org-e-latex-compile
- (org-e-publish-org-to 'e-latex filename ".tex" plist pub-dir)))
-
-(defun org-e-publish-org-to-html (plist filename pub-dir)
- "Publish an org file to HTML.
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (org-e-publish-org-to 'e-html filename ".html" plist pub-dir))
-
-;; TODO: Not implemented yet.
-;; (defun org-e-publish-org-to-org (plist filename pub-dir)
-;; "Publish an org file to HTML.
-;;
-;; FILENAME is the filename of the Org file to be published. PLIST
-;; is the property list for the given project. PUB-DIR is the
-;; publishing directory.
-;;
-;; Return output file name."
-;; (org-e-publish-org-to "org" plist filename pub-dir))
-
-(defun org-e-publish-org-to-ascii (plist filename pub-dir)
- "Publish an Org file to ASCII.
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (org-e-publish-org-to
- 'e-ascii filename ".txt" `(:ascii-charset ascii ,@plist) pub-dir))
-
-(defun org-e-publish-org-to-latin1 (plist filename pub-dir)
- "Publish an Org file to Latin-1.
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (org-e-publish-org-to
- 'e-ascii filename ".txt" `(:ascii-charset latin1 ,@plist) pub-dir))
-
-(defun org-e-publish-org-to-utf8 (plist filename pub-dir)
- "Publish an org file to UTF-8.
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (org-e-publish-org-to
- 'e-ascii filename ".txt" `(:ascii-charset utf-8 ,@plist) pub-dir))
-
-(defun org-e-publish-attachment (plist filename pub-dir)
- "Publish a file with no transformation of any kind.
-
-FILENAME is the filename of the Org file to be published. PLIST
-is the property list for the given project. PUB-DIR is the
-publishing directory.
-
-Return output file name."
- (unless (file-directory-p pub-dir)
- (make-directory pub-dir t))
- (or (equal (expand-file-name (file-name-directory filename))
- (file-name-as-directory (expand-file-name pub-dir)))
- (copy-file filename
- (expand-file-name (file-name-nondirectory filename) pub-dir)
- t)))
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Publishing files, sets of files, and indices
-
-(defun org-e-publish-file (filename &optional project no-cache)
- "Publish file FILENAME from PROJECT.
-If NO-CACHE is not nil, do not initialize org-e-publish-cache and
-write it to disk. This is needed, since this function is used to
-publish single files, when entire projects are published.
-See `org-e-publish-projects'."
- (let* ((project
- (or project
- (or (org-e-publish-get-project-from-filename filename)
- (error "File %s not part of any known project"
- (abbreviate-file-name filename)))))
- (project-plist (cdr project))
- (ftname (expand-file-name filename))
- (publishing-function
- (or (plist-get project-plist :publishing-function)
- 'org-e-publish-org-to-ascii))
- (base-dir
- (file-name-as-directory
- (expand-file-name
- (or (plist-get project-plist :base-directory)
- (error "Project %s does not have :base-directory defined"
- (car project))))))
- (pub-dir
- (file-name-as-directory
- (file-truename
- (or (eval (plist-get project-plist :publishing-directory))
- (error "Project %s does not have :publishing-directory defined"
- (car project))))))
- tmp-pub-dir)
-
- (unless no-cache (org-e-publish-initialize-cache (car project)))
-
- (setq tmp-pub-dir
- (file-name-directory
- (concat pub-dir
- (and (string-match (regexp-quote base-dir) ftname)
- (substring ftname (match-end 0))))))
- (if (listp publishing-function)
- ;; allow chain of publishing functions
- (mapc (lambda (f)
- (when (org-e-publish-needed-p
- filename pub-dir f tmp-pub-dir base-dir)
- (funcall f project-plist filename tmp-pub-dir)
- (org-e-publish-update-timestamp filename pub-dir f base-dir)))
- publishing-function)
- (when (org-e-publish-needed-p
- filename pub-dir publishing-function tmp-pub-dir base-dir)
- (funcall publishing-function project-plist filename tmp-pub-dir)
- (org-e-publish-update-timestamp
- filename pub-dir publishing-function base-dir)))
- (unless no-cache (org-e-publish-write-cache-file))))
-
-(defun org-e-publish-projects (projects)
- "Publish all files belonging to the PROJECTS alist.
-If `:auto-sitemap' is set, publish the sitemap too. If
-`:makeindex' is set, also produce a file theindex.org."
- (mapc
- (lambda (project)
- ;; Each project uses its own cache file:
- (org-e-publish-initialize-cache (car project))
- (let* ((project-plist (cdr project))
- (exclude-regexp (plist-get project-plist :exclude))
- (sitemap-p (plist-get project-plist :auto-sitemap))
- (sitemap-filename (or (plist-get project-plist :sitemap-filename)
- "sitemap.org"))
- (sitemap-function (or (plist-get project-plist :sitemap-function)
- 'org-e-publish-org-sitemap))
- (org-sitemap-date-format
- (or (plist-get project-plist :sitemap-date-format)
- org-e-publish-sitemap-date-format))
- (org-sitemap-file-entry-format
- (or (plist-get project-plist :sitemap-file-entry-format)
- org-e-publish-sitemap-file-entry-format))
- (preparation-function
- (plist-get project-plist :preparation-function))
- (completion-function (plist-get project-plist :completion-function))
- (files (org-e-publish-get-base-files project exclude-regexp)) file)
- (when preparation-function (run-hooks 'preparation-function))
- (if sitemap-p (funcall sitemap-function project sitemap-filename))
- (dolist (file files) (org-e-publish-file file project t))
- (when (plist-get project-plist :makeindex)
- (org-e-publish-index-generate-theindex
- project (plist-get project-plist :base-directory))
- (org-e-publish-file
- (expand-file-name
- "theindex.org" (plist-get project-plist :base-directory))
- project t))
- (when completion-function (run-hooks 'completion-function))
- (org-e-publish-write-cache-file)))
- (org-e-publish-expand-projects projects)))
-
-(defun org-e-publish-org-sitemap (project &optional sitemap-filename)
- "Create a sitemap of pages in set defined by PROJECT.
-Optionally set the filename of the sitemap with SITEMAP-FILENAME.
-Default for SITEMAP-FILENAME is 'sitemap.org'."
- (let* ((project-plist (cdr project))
- (dir (file-name-as-directory
- (plist-get project-plist :base-directory)))
- (localdir (file-name-directory dir))
- (indent-str (make-string 2 ?\ ))
- (exclude-regexp (plist-get project-plist :exclude))
- (files (nreverse
- (org-e-publish-get-base-files project exclude-regexp)))
- (sitemap-filename (concat dir (or sitemap-filename "sitemap.org")))
- (sitemap-title (or (plist-get project-plist :sitemap-title)
- (concat "Sitemap for project " (car project))))
- (sitemap-style (or (plist-get project-plist :sitemap-style)
- 'tree))
- (sitemap-sans-extension
- (plist-get project-plist :sitemap-sans-extension))
- (visiting (find-buffer-visiting sitemap-filename))
- (ifn (file-name-nondirectory sitemap-filename))
- file sitemap-buffer)
- (with-current-buffer (setq sitemap-buffer
- (or visiting (find-file sitemap-filename)))
- (erase-buffer)
- (insert (concat "#+TITLE: " sitemap-title "\n\n"))
- (while (setq file (pop files))
- (let ((fn (file-name-nondirectory file))
- (link (file-relative-name file dir))
- (oldlocal localdir))
- (when sitemap-sans-extension
- (setq link (file-name-sans-extension link)))
- ;; sitemap shouldn't list itself
- (unless (equal (file-truename sitemap-filename)
- (file-truename file))
- (if (eq sitemap-style 'list)
- (message "Generating list-style sitemap for %s" sitemap-title)
- (message "Generating tree-style sitemap for %s" sitemap-title)
- (setq localdir (concat (file-name-as-directory dir)
- (file-name-directory link)))
- (unless (string= localdir oldlocal)
- (if (string= localdir dir)
- (setq indent-str (make-string 2 ?\ ))
- (let ((subdirs
- (split-string
- (directory-file-name
- (file-name-directory
- (file-relative-name localdir dir))) "/"))
- (subdir "")
- (old-subdirs (split-string
- (file-relative-name oldlocal dir) "/")))
- (setq indent-str (make-string 2 ?\ ))
- (while (string= (car old-subdirs) (car subdirs))
- (setq indent-str (concat indent-str (make-string 2 ?\ )))
- (pop old-subdirs)
- (pop subdirs))
- (dolist (d subdirs)
- (setq subdir (concat subdir d "/"))
- (insert (concat indent-str " + " d "\n"))
- (setq indent-str (make-string
- (+ (length indent-str) 2) ?\ )))))))
- ;; This is common to 'flat and 'tree
- (let ((entry
- (org-e-publish-format-file-entry
- org-sitemap-file-entry-format file project-plist))
- (regexp "\\(.*\\)\\[\\([^][]+\\)\\]\\(.*\\)"))
- (cond ((string-match-p regexp entry)
- (string-match regexp entry)
- (insert (concat indent-str " + " (match-string 1 entry)
- "[[file:" link "]["
- (match-string 2 entry)
- "]]" (match-string 3 entry) "\n")))
- (t
- (insert (concat indent-str " + [[file:" link "]["
- entry
- "]]\n"))))))))
- (save-buffer))
- (or visiting (kill-buffer sitemap-buffer))))
-
-(defun org-e-publish-format-file-entry (fmt file project-plist)
- (format-spec fmt
- `((?t . ,(org-e-publish-find-title file t))
- (?d . ,(format-time-string org-sitemap-date-format
- (org-e-publish-find-date file)))
- (?a . ,(or (plist-get project-plist :author) user-full-name)))))
-
-(defun org-e-publish-find-title (file &optional reset)
- "Find the title of FILE in project."
- (or
- (and (not reset) (org-e-publish-cache-get-file-property file :title nil t))
- (let* ((visiting (find-buffer-visiting file))
- (buffer (or visiting (find-file-noselect file)))
- title)
- (with-current-buffer buffer
- (org-mode)
- (setq title
- (or (plist-get (org-export-get-environment) :title)
- (file-name-nondirectory (file-name-sans-extension file)))))
- (unless visiting (kill-buffer buffer))
- (org-e-publish-cache-set-file-property file :title title)
- title)))
-
-(defun org-e-publish-find-date (file)
- "Find the date of FILE in project.
-If FILE provides a #+date keyword use it else use the file
-system's modification time.
-
-It returns time in `current-time' format."
- (let* ((visiting (find-buffer-visiting file))
- (file-buf (or visiting (find-file-noselect file nil)))
- (date (plist-get
- (with-current-buffer file-buf
- (org-mode)
- (org-export--get-inbuffer-options))
- :date)))
- (unless visiting (kill-buffer file-buf))
- (if date (org-time-string-to-time date)
- (when (file-exists-p file)
- (nth 5 (file-attributes file))))))
-
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Interactive publishing functions
-
-;;;###autoload
-(defalias 'org-e-publish-project 'org-e-publish)
-
-;;;###autoload
-(defun org-e-publish (project &optional force)
- "Publish PROJECT."
- (interactive
- (list
- (assoc (org-icompleting-read
- "Publish project: "
- org-e-publish-project-alist nil t)
- org-e-publish-project-alist)
- current-prefix-arg))
- (setq org-e-publish-initial-buffer (current-buffer))
- (save-window-excursion
- (let* ((org-e-publish-use-timestamps-flag
- (if force nil org-e-publish-use-timestamps-flag)))
- (org-e-publish-projects
- (if (stringp project)
- ;; If this function is called in batch mode, project is
- ;; still a string here.
- (list (assoc project org-e-publish-project-alist))
- (list project))))))
-
-;;;###autoload
-(defun org-e-publish-all (&optional force)
- "Publish all projects.
-With prefix argument, remove all files in the timestamp
-directory and force publishing all files."
- (interactive "P")
- (when force (org-e-publish-remove-all-timestamps))
- (save-window-excursion
- (let ((org-e-publish-use-timestamps-flag
- (if force nil org-e-publish-use-timestamps-flag)))
- (org-e-publish-projects org-e-publish-project-alist))))
-
-
-;;;###autoload
-(defun org-e-publish-current-file (&optional force)
- "Publish the current file.
-With prefix argument, force publish the file."
- (interactive "P")
- (save-window-excursion
- (let ((org-e-publish-use-timestamps-flag
- (if force nil org-e-publish-use-timestamps-flag)))
- (org-e-publish-file (buffer-file-name (buffer-base-buffer))))))
-
-;;;###autoload
-(defun org-e-publish-current-project (&optional force)
- "Publish the project associated with the current file.
-With a prefix argument, force publishing of all files in
-the project."
- (interactive "P")
- (save-window-excursion
- (let ((project (org-e-publish-get-project-from-filename
- (buffer-file-name (buffer-base-buffer)) 'up))
- (org-e-publish-use-timestamps-flag
- (if force nil org-e-publish-use-timestamps-flag)))
- (if project (org-e-publish project)
- (error "File %s is not part of any known project"
- (buffer-file-name (buffer-base-buffer)))))))
-
-
-
-;;; Index generation
-
-(defun org-e-publish-collect-index (tree backend info)
- "Update index for a file with TREE in cache.
-
-BACKEND is the back-end being used for transcoding. INFO is
-a plist containing publishing options.
-
-The index relative to current file is stored as an alist. An
-association has the following shape: \(TERM FILE-NAME PARENT),
-where TERM is the indexed term, as a string, FILE-NAME is the
-original full path of the file where the term in encountered, and
-PARENT is the headline element containing the original index
-keyword."
- (org-e-publish-cache-set-file-property
- (plist-get info :input-file) :index
- (delete-dups
- (org-element-map
- tree 'keyword
- (lambda (k)
- (when (string= (downcase (org-element-property :key k))
- "index")
- (let ((index (org-element-property :value k))
- (parent (org-export-get-parent-headline k)))
- (list index (plist-get info :input-file) parent))))
- info)))
- ;; Return parse-tree to avoid altering output.
- tree)
-
-(defun org-e-publish-index-generate-theindex (project directory)
- "Retrieve full index from cache and build \"theindex.org\".
-PROJECT is the project the index relates to. DIRECTORY is the
-publishing directory."
- (let ((all-files (org-e-publish-get-base-files
- project (plist-get (cdr project) :exclude)))
- full-index)
- ;; Compile full index.
- (mapc
- (lambda (file)
- (let ((index (org-e-publish-cache-get-file-property file :index)))
- (dolist (term index)
- (unless (member term full-index) (push term full-index)))))
- all-files)
- ;; Sort it alphabetically.
- (setq full-index
- (sort full-index (lambda (a b) (string< (downcase (car a))
- (downcase (car b))))))
- ;; Fill "theindex.org".
- (with-temp-buffer
- (insert "#+TITLE: Index\n#+OPTIONS: num:nil author:nil\n")
- (let ((current-letter nil) (last-entry nil))
- (dolist (idx full-index)
- (let* ((entry (org-split-string (car idx) "!"))
- (letter (upcase (substring (car entry) 0 1)))
- ;; Transform file into a path relative to publishing
- ;; directory.
- (file (file-relative-name
- (nth 1 idx)
- (plist-get (cdr project) :base-directory))))
- ;; Check if another letter has to be inserted.
- (unless (string= letter current-letter)
- (insert (format "* %s\n" letter)))
- ;; Compute the first difference between last entry and
- ;; current one: it tells the level at which new items
- ;; should be added.
- (let* ((rank (loop for n from 0 to (length entry)
- unless (equal (nth n entry) (nth n last-entry))
- return n))
- (len (length (nthcdr rank entry))))
- ;; For each term after the first difference, create
- ;; a new sub-list with the term as body. Moreover,
- ;; linkify the last term.
- (dotimes (n len)
- (insert
- (concat
- (make-string (* (+ rank n) 2) ? ) " - "
- (if (not (= (1- len) n)) (nth (+ rank n) entry)
- ;; Last term: Link it to TARGET, if possible.
- (let ((target (nth 2 idx)))
- (format
- "[[%s][%s]]"
- ;; Destination.
- (cond
- ((not target) (format "file:%s" file))
- ((let ((id (org-element-property :id target)))
- (and id (format "id:%s" id))))
- ((let ((id (org-element-property :custom-id target)))
- (and id (format "file:%s::#%s" file id))))
- (t (format "file:%s::*%s" file
- (org-element-property :raw-value target))))
- ;; Description.
- (car (last entry)))))
- "\n"))))
- (setq current-letter letter last-entry entry))))
- ;; Write index.
- (write-file (expand-file-name "theindex.org" directory)))))
-
-
-
-;;; Caching functions
-
-(defun org-e-publish-write-cache-file (&optional free-cache)
- "Write `org-e-publish-cache' to file.
-If FREE-CACHE, empty the cache."
- (unless org-e-publish-cache
- (error "`org-e-publish-write-cache-file' called, but no cache present"))
-
- (let ((cache-file (org-e-publish-cache-get ":cache-file:")))
- (unless cache-file
- (error "Cannot find cache-file name in `org-e-publish-write-cache-file'"))
- (with-temp-file cache-file
- (let (print-level print-length)
- (insert "(setq org-e-publish-cache (make-hash-table :test 'equal :weakness nil :size 100))\n")
- (maphash (lambda (k v)
- (insert
- (format (concat "(puthash %S "
- (if (or (listp v) (symbolp v))
- "'" "")
- "%S org-e-publish-cache)\n") k v)))
- org-e-publish-cache)))
- (when free-cache (org-e-publish-reset-cache))))
-
-(defun org-e-publish-initialize-cache (project-name)
- "Initialize the projects cache if not initialized yet and return it."
-
- (unless project-name
- (error "Cannot initialize `org-e-publish-cache' without projects name in `org-e-publish-initialize-cache'"))
-
- (unless (file-exists-p org-e-publish-timestamp-directory)
- (make-directory org-e-publish-timestamp-directory t))
- (unless (file-directory-p org-e-publish-timestamp-directory)
- (error "Org publish timestamp: %s is not a directory"
- org-e-publish-timestamp-directory))
-
- (unless (and org-e-publish-cache
- (string= (org-e-publish-cache-get ":project:") project-name))
- (let* ((cache-file
- (concat
- (expand-file-name org-e-publish-timestamp-directory)
- project-name ".cache"))
- (cexists (file-exists-p cache-file)))
-
- (when org-e-publish-cache (org-e-publish-reset-cache))
-
- (if cexists (load-file cache-file)
- (setq org-e-publish-cache
- (make-hash-table :test 'equal :weakness nil :size 100))
- (org-e-publish-cache-set ":project:" project-name)
- (org-e-publish-cache-set ":cache-file:" cache-file))
- (unless cexists (org-e-publish-write-cache-file nil))))
- org-e-publish-cache)
-
-(defun org-e-publish-reset-cache ()
- "Empty org-e-publish-cache and reset it nil."
- (message "%s" "Resetting org-e-publish-cache")
- (when (hash-table-p org-e-publish-cache)
- (clrhash org-e-publish-cache))
- (setq org-e-publish-cache nil))
-
-(defun org-e-publish-cache-file-needs-publishing
- (filename &optional pub-dir pub-func base-dir)
- "Check the timestamp of the last publishing of FILENAME.
-Non-nil if the file needs publishing. The function also checks
-if any included files have been more recently published, so that
-the file including them will be republished as well."
- (unless org-e-publish-cache
- (error
- "`org-e-publish-cache-file-needs-publishing' called, but no cache present"))
- (let* ((case-fold-search t)
- (key (org-e-publish-timestamp-filename filename pub-dir pub-func))
- (pstamp (org-e-publish-cache-get key))
- (visiting (find-buffer-visiting filename))
- included-files-ctime buf)
-
- (when (equal (file-name-extension filename) "org")
- (setq buf (find-file (expand-file-name filename)))
- (with-current-buffer buf
- (goto-char (point-min))
- (while (re-search-forward
- "^#\\+INCLUDE:[ \t]+\"\\([^\t\n\r\"]*\\)\"[ \t]*.*$" nil t)
- (let* ((included-file (expand-file-name (match-string 1))))
- (add-to-list
- 'included-files-ctime
- (org-e-publish-cache-ctime-of-src included-file base-dir)
- t))))
- ;; FIXME: don't kill current buffer.
- (unless visiting (kill-buffer buf)))
- (if (null pstamp) t
- (let ((ctime (org-e-publish-cache-ctime-of-src filename base-dir)))
- (or (< pstamp ctime)
- (when included-files-ctime
- (not (null (delq nil (mapcar (lambda(ct) (< ctime ct))
- included-files-ctime))))))))))
-
-(defun org-e-publish-cache-set-file-property
- (filename property value &optional project-name)
- "Set the VALUE for a PROPERTY of file FILENAME in publishing cache to VALUE.
-Use cache file of PROJECT-NAME. If the entry does not exist, it
-will be created. Return VALUE."
- ;; Evtl. load the requested cache file:
- (if project-name (org-e-publish-initialize-cache project-name))
- (let ((pl (org-e-publish-cache-get filename)))
- (if pl (progn (plist-put pl property value) value)
- (org-e-publish-cache-get-file-property
- filename property value nil project-name))))
-
-(defun org-e-publish-cache-get-file-property
- (filename property &optional default no-create project-name)
- "Return the value for a PROPERTY of file FILENAME in publishing cache.
-Use cache file of PROJECT-NAME. Return the value of that PROPERTY
-or DEFAULT, if the value does not yet exist. If the entry will
-be created, unless NO-CREATE is not nil."
- ;; Evtl. load the requested cache file:
- (if project-name (org-e-publish-initialize-cache project-name))
- (let ((pl (org-e-publish-cache-get filename)) retval)
- (if pl
- (if (plist-member pl property)
- (setq retval (plist-get pl property))
- (setq retval default))
- ;; no pl yet:
- (unless no-create
- (org-e-publish-cache-set filename (list property default)))
- (setq retval default))
- retval))
-
-(defun org-e-publish-cache-get (key)
- "Return the value stored in `org-e-publish-cache' for key KEY.
-Returns nil, if no value or nil is found, or the cache does not
-exist."
- (unless org-e-publish-cache
- (error "`org-e-publish-cache-get' called, but no cache present"))
- (gethash key org-e-publish-cache))
-
-(defun org-e-publish-cache-set (key value)
- "Store KEY VALUE pair in `org-e-publish-cache'.
-Returns value on success, else nil."
- (unless org-e-publish-cache
- (error "`org-e-publish-cache-set' called, but no cache present"))
- (puthash key value org-e-publish-cache))
-
-(defun org-e-publish-cache-ctime-of-src (f base-dir)
- "Get the FILENAME ctime as an integer."
- (let ((attr (file-attributes
- (expand-file-name (or (file-symlink-p f) f) base-dir))))
- (+ (lsh (car (nth 5 attr)) 16)
- (cadr (nth 5 attr)))))
-
-
-(provide 'org-e-publish)
-
-;;; org-e-publish.el ends here
diff --git a/contrib/lisp/org-e-texinfo.el b/contrib/lisp/org-e-texinfo.el
deleted file mode 100644
index a19139f..0000000
--- a/contrib/lisp/org-e-texinfo.el
+++ /dev/null
@@ -1,1844 +0,0 @@
-;;; org-e-texinfo.el --- Texinfo Back-End For Org Export Engine
-
-;; Copyright (C) 2012 Jonathan Leech-Pepin
-;; Author: Jonathan Leech-Pepin <jonathan.leechpepin at gmail dot com>
-;; Keywords: outlines, hypermedia, calendar, wp
-;;
-;; This file is not part of GNU Emacs.
-;;
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;;
-;; This library implements a Texinfo back-end for Org generic
-;; exporter.
-;;
-;; To test it, run
-;;
-;; M-: (org-export-to-buffer 'e-texinfo "*Test e-texinfo*") RET
-;;
-;; in an org-mode buffer then switch to the buffer to see the Texinfo
-;; export. See contrib/lisp/org-export.el for more details on how
-;; this exporter works.
-;;
-;; It introduces eight new buffer keywords: "TEXINFO_CLASS",
-;; "TEXINFO_FILENAME", "TEXINFO_HEADER", "TEXINFO_DIR_CATEGORY",
-;; "TEXINFO_DIR_TITLE", "TEXINFO_DIR_DESC" "SUBTITLE" and "SUBAUTHOR".
-;;
-;; To include inline code snippets (for example for generating @kbd{}
-;; and @key{} commands), the following export-snippet keys are
-;; accepted:
-;;
-;; info
-;; e-info
-;; e-texinfo
-;;
-;; You can add them for export snippets via any of the below:
-;;
-;; (add-to-list 'org-export-snippet-translation-alist
-;; '("e-info" . "e-texinfo"))
-;; (add-to-list 'org-export-snippet-translation-alist
-;; '("e-texinfo" . "e-texinfo"))
-;; (add-to-list 'org-export-snippet-translation-alist
-;; '("info" . "e-texinfo"))
-;;
-
-;;; Code:
-
-(eval-when-compile (require 'cl))
-(require 'org-export)
-
-(defvar orgtbl-exp-regexp)
-
-
-;;; Define Back-End
-
-(defvar org-e-texinfo-translate-alist
- '((babel-call . org-e-texinfo-babel-call)
- (bold . org-e-texinfo-bold)
- (center-block . org-e-texinfo-center-block)
- (clock . org-e-texinfo-clock)
- (code . org-e-texinfo-code)
- (comment . org-e-texinfo-comment)
- (comment-block . org-e-texinfo-comment-block)
- (drawer . org-e-texinfo-drawer)
- (dynamic-block . org-e-texinfo-dynamic-block)
- (entity . org-e-texinfo-entity)
- (example-block . org-e-texinfo-example-block)
- (export-block . org-e-texinfo-export-block)
- (export-snippet . org-e-texinfo-export-snippet)
- (fixed-width . org-e-texinfo-fixed-width)
- (footnote-definition . org-e-texinfo-footnote-definition)
- (footnote-reference . org-e-texinfo-footnote-reference)
- (headline . org-e-texinfo-headline)
- (horizontal-rule . org-e-texinfo-horizontal-rule)
- (inline-babel-call . org-e-texinfo-inline-babel-call)
- (inline-src-block . org-e-texinfo-inline-src-block)
- (inlinetask . org-e-texinfo-inlinetask)
- (italic . org-e-texinfo-italic)
- (item . org-e-texinfo-item)
- (keyword . org-e-texinfo-keyword)
- (latex-environment . org-e-texinfo-latex-environment)
- (latex-fragment . org-e-texinfo-latex-fragment)
- (line-break . org-e-texinfo-line-break)
- (link . org-e-texinfo-link)
- (macro . org-e-texinfo-macro)
- (paragraph . org-e-texinfo-paragraph)
- (plain-list . org-e-texinfo-plain-list)
- (plain-text . org-e-texinfo-plain-text)
- (planning . org-e-texinfo-planning)
- (property-drawer . org-e-texinfo-property-drawer)
- (quote-block . org-e-texinfo-quote-block)
- (quote-section . org-e-texinfo-quote-section)
- (radio-target . org-e-texinfo-radio-target)
- (section . org-e-texinfo-section)
- (special-block . org-e-texinfo-special-block)
- (src-block . org-e-texinfo-src-block)
- (statistics-cookie . org-e-texinfo-statistics-cookie)
- (strike-through . org-e-texinfo-strike-through)
- (subscript . org-e-texinfo-subscript)
- (superscript . org-e-texinfo-superscript)
- (table . org-e-texinfo-table)
- (table-cell . org-e-texinfo-table-cell)
- (table-row . org-e-texinfo-table-row)
- (target . org-e-texinfo-target)
- (template . org-e-texinfo-template)
- (timestamp . org-e-texinfo-timestamp)
- (underline . org-e-texinfo-underline)
- (verbatim . org-e-texinfo-verbatim)
- (verse-block . org-e-texinfo-verse-block))
- "Alist between element or object types and translators.")
-
-(defconst org-e-texinfo-options-alist
- '((:texinfo-filename "TEXINFO_FILENAME" nil org-e-texinfo-filename t)
- (:texinfo-class "TEXINFO_CLASS" nil org-e-texinfo-default-class t)
- (:texinfo-header "TEXINFO_HEADER" nil nil newline)
- (:subtitle "SUBTITLE" nil nil newline)
- (:subauthor "SUBAUTHOR" nil nil newline)
- (:texinfo-dircat "TEXINFO_DIR_CATEGORY" nil nil t)
- (:texinfo-dirtitle "TEXINFO_DIR_TITLE" nil nil t)
- (:texinfo-dirdesc "TEXINFO_DIR_DESC" nil nil t))
- "Alist between Texinfo export properties and ways to set them.
-See `org-export-options-alist' for more information on the
-structure of the values.
-
-SUBAUTHOR and SUBTITLE are for the inclusion of additional author
-and title information beyond the initial variable.")
-
-(defconst org-e-texinfo-filters-alist
- '((:filter-headline . org-e-texinfo-filter-section-blank-lines)
- (:filter-section . org-e-texinfo-filter-section-blank-lines))
- "Alist between filters keywords and back-end specific filters.
- See `org-export-filters-alist' for more information")
-
-
-;;; Internal Variables
-
-;; Add TEXINFO to the list of available of available export blocks.
-(add-to-list 'org-element-block-name-alist
- '("TEXINFO" . org-element-export-block-parser))
-
-;;; User Configurable Variables
-
-(defgroup org-export-e-texinfo nil
- "Options for exporting Org mode files to Texinfo."
- :tag "Org Export Texinfo"
- :group 'org-export)
-
-;;; Preamble
-
-(defcustom org-e-texinfo-filename nil
- "Default filename for texinfo output."
- :group 'org-export-e-texinfo
- :type '(string :tag "Export Filename"))
-
-(defcustom org-e-texinfo-default-class "info"
- "The default Texinfo class."
- :group 'org-export-e-texinfo
- :type '(string :tag "Texinfo class"))
-
-(defcustom org-e-texinfo-classes
- '(("info"
- "\\input texinfo @c -*- texinfo -*-"
- ("@chapter %s" . "@unnumbered %s")
- ("@section %s" . "@unnumberedsec %s")
- ("@subsection %s" . "@unnumberedsubsec %s")
- ("@subsubsection %s" . "@unnumberedsubsubsec %s")))
- "Alist of Texinfo classes and associated header and structure.
-If #+Texinfo_CLASS is set in the buffer, use its value and the
-associated information. Here is the structure of each cell:
-
- \(class-name
- header-string
- \(numbered-section . unnumbered-section\)
- ...\)
-
-The sectioning structure
-------------------------
-
-The sectioning structure of the class is given by the elements
-following the header string. For each sectioning level, a number
-of strings is specified. A %s formatter is mandatory in each
-section string and will be replaced by the title of the section.
-
-Instead of a list of sectioning commands, you can also specify
-a function name. That function will be called with two
-parameters, the \(reduced) level of the headline, and a predicate
-non-nil when the headline should be numbered. It must return
-a format string in which the section title will be added."
- :group 'org-export-e-texinfo
- :type '(repeat
- (list (string :tag "Texinfo class")
- (string :tag "Texinfo header")
- (repeat :tag "Levels" :inline t
- (choice
- (cons :tag "Heading"
- (string :tag " numbered")
- (string :tag "unnumbered"))
- (function :tag "Hook computing sectioning"))))))
-
-;;; Headline
-
-(defcustom org-e-texinfo-format-headline-function nil
- "Function to format headline text.
-
-This function will be called with 5 arguments:
-TODO the todo keyword (string or nil).
-TODO-TYPE the type of todo (symbol: `todo', `done', nil)
-PRIORITY the priority of the headline (integer or nil)
-TEXT the main headline text (string).
-TAGS the tags as a list of strings (list of strings or nil).
-
-The function result will be used in the section format string.
-
-As an example, one could set the variable to the following, in
-order to reproduce the default set-up:
-
-\(defun org-e-texinfo-format-headline (todo todo-type priority text tags)
- \"Default format function for an headline.\"
- \(concat (when todo
- \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo))
- \(when priority
- \(format \"\\\\framebox{\\\\#%c} \" priority))
- text
- \(when tags
- \(format \"\\\\hfill{}\\\\textsc{%s}\"
- \(mapconcat 'identity tags \":\"))))"
- :group 'org-export-e-texinfo
- :type 'function)
-
-
-;;; Footnotes
-;;
-;; Footnotes are inserted directly
-
-;;; Timestamps
-
-(defcustom org-e-texinfo-active-timestamp-format "@emph{%s}"
- "A printf format string to be applied to active timestamps."
- :group 'org-export-e-texinfo
- :type 'string)
-
-(defcustom org-e-texinfo-inactive-timestamp-format "@emph{%s}"
- "A printf format string to be applied to inactive timestamps."
- :group 'org-export-e-texinfo
- :type 'string)
-
-(defcustom org-e-texinfo-diary-timestamp-format "@emph{%s}"
- "A printf format string to be applied to diary timestamps."
- :group 'org-export-e-texinfo
- :type 'string)
-
-;;; Links
-
-(defcustom org-e-texinfo-link-with-unknown-path-format "@indicateurl{%s}"
- "Format string for links with unknown path type."
- :group 'org-export-e-texinfo
- :type 'string)
-
-;;; Tables
-
-(defcustom org-e-texinfo-tables-verbatim nil
- "When non-nil, tables are exported verbatim."
- :group 'org-export-e-texinfo
- :type 'boolean)
-
-(defcustom org-e-texinfo-table-scientific-notation "%s\\,(%s)"
- "Format string to display numbers in scientific notation.
-The format should have \"%s\" twice, for mantissa and exponent
-\(i.e. \"%s\\\\times10^{%s}\").
-
-When nil, no transformation is made."
- :group 'org-export-e-texinfo
- :type '(choice
- (string :tag "Format string")
- (const :tag "No formatting")))
-
-(defcustom org-e-texinfo-def-table-markup "@samp"
- "Default setting for @table environments.")
-
-;;; Text markup
-
-(defcustom org-e-texinfo-text-markup-alist '((bold . "@strong{%s}")
- (code . code)
- (italic . "@emph{%s}")
- (verbatim . verb)
- (comment . "@c %s"))
- "Alist of Texinfo expressions to convert text markup.
-
-The key must be a symbol among `bold', `italic' and `comment'.
-The value is a formatting string to wrap fontified text with.
-
-Value can also be set to the following symbols: `verb' and
-`code'. For the former, Org will use \"@verb\" to
-create a format string and select a delimiter character that
-isn't in the string. For the latter, Org will use \"@code\"
-to typeset and try to protect special characters.
-
-If no association can be found for a given markup, text will be
-returned as-is."
- :group 'org-export-e-texinfo
- :type 'alist
- :options '(bold code italic verbatim comment))
-
-;;; Drawers
-
-(defcustom org-e-texinfo-format-drawer-function nil
- "Function called to format a drawer in Texinfo code.
-
-The function must accept two parameters:
- NAME the drawer name, like \"LOGBOOK\"
- CONTENTS the contents of the drawer.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-texinfo-format-drawer-default \(name contents\)
- \"Format a drawer element for Texinfo export.\"
- contents\)"
- :group 'org-export-e-texinfo
- :type 'function)
-
-;;; Inlinetasks
-
-(defcustom org-e-texinfo-format-inlinetask-function nil
- "Function called to format an inlinetask in Texinfo code.
-
-The function must accept six parameters:
- TODO the todo keyword, as a string
- TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
- PRIORITY the inlinetask priority, as a string
- NAME the inlinetask name, as a string.
- TAGS the inlinetask tags, as a list of strings.
- CONTENTS the contents of the inlinetask, as a string.
-
-The function should return the string to be exported.
-
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-e-texinfo-format-inlinetask \(todo type priority name tags contents\)
-\"Format an inline task element for Texinfo export.\"
- \(let ((full-title
- \(concat
- \(when todo
- \(format \"@strong{%s} \" todo))
- \(when priority (format \"#%c \" priority))
- title
- \(when tags
- \(format \":%s:\"
- \(mapconcat 'identity tags \":\")))))
- \(format (concat \"@center %s\n\n\"
- \"%s\"
- \"\n\"))
- full-title contents))"
- :group 'org-export-e-texinfo
- :type 'function)
-
-;;; Src blocks
-;;
-;; Src Blocks are example blocks, except for LISP
-
-;;; Plain text
-
-(defcustom org-e-texinfo-quotes
- '(("quotes"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "``")
- ("\\(\\S-\\)\"" . "''")
- ("\\(\\s-\\|(\\|^\\)'" . "`")))
- "Alist for quotes to use when converting english double-quotes.
-
-The CAR of each item in this alist is the language code.
-The CDR of each item in this alist is a list of three CONS:
-- the first CONS defines the opening quote;
-- the second CONS defines the closing quote;
-- the last CONS defines single quotes.
-
-For each item in a CONS, the first string is a regexp
-for allowed characters before/after the quote, the second
-string defines the replacement string for this quote."
- :group 'org-export-e-texinfo
- :type '(list
- (cons :tag "Opening quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))
- (cons :tag "Closing quote"
- (string :tag "Regexp for char after ")
- (string :tag "Replacement quote "))
- (cons :tag "Single quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))))
-
-;;; Compilation
-
-(defcustom org-e-texinfo-info-process
- '("makeinfo %f")
- "Commands to process a texinfo file to an INFO file.
-This is list of strings, each of them will be given to the shell
-as a command. %f in the command will be replaced by the full
-file name, %b by the file base name \(i.e without extension) and
-%o by the base directory of the file."
- :group 'org-export-texinfo
- :type '(repeat :tag "Shell command sequence"
- (string :tag "Shell command")))
-
-
-;;; Internal Functions
-
-(defun org-e-texinfo-filter-section-blank-lines (headline back-end info)
- "Filter controlling number of blank lines after a section."
- (let ((blanks (make-string 2 ?\n)))
- (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" blanks headline)))
-
-(defun org-e-texinfo--find-copying (info)
- "Retrieve the headline identified by the property :copying:.
-
-INFO is the plist containing the export options and tree. It is
-used to find and extract the single desired headline. This
-cannot be treated as a standard headline since it must be
-inserted in a specific location."
- (let (copying)
- (org-element-map (plist-get info :parse-tree) 'headline
- (lambda (copy)
- (when (org-element-property :copying copy)
- (push copy copying))) info 't)
- ;; Retrieve the single entry
- (car copying)))
-
-(defun org-e-texinfo--find-verb-separator (s)
- "Return a character not used in string S.
-This is used to choose a separator for constructs like \\verb."
- (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
- (loop for c across ll
- when (not (string-match (regexp-quote (char-to-string c)) s))
- return (char-to-string c))))
-
-(defun org-e-texinfo--make-option-string (options)
- "Return a comma separated string of keywords and values.
-OPTIONS is an alist where the key is the options keyword as
-a string, and the value a list containing the keyword value, or
-nil."
- (mapconcat (lambda (pair)
- (concat (first pair)
- (when (> (length (second pair)) 0)
- (concat "=" (second pair)))))
- options
- ","))
-
-(defun org-e-texinfo--quotation-marks (text info)
- "Export quotation marks using ` and ' as the markers.
-TEXT is a string containing quotation marks to be replaced. INFO
-is a plist used as a communication channel."
- (mapc (lambda(l)
- (let ((start 0))
- (while (setq start (string-match (car l) text start))
- (let ((new-quote (concat (match-string 1 text) (cdr l))))
- (setq text (replace-match new-quote t t text))))))
- (cdr org-e-texinfo-quotes))
- text)
-
-(defun org-e-texinfo--text-markup (text markup)
- "Format TEXT depending on MARKUP text markup.
-See `org-e-texinfo-text-markup-alist' for details."
- (let ((fmt (cdr (assq markup org-e-texinfo-text-markup-alist))))
- (cond
- ;; No format string: Return raw text.
- ((not fmt) text)
- ((eq 'verb fmt)
- (let ((separator (org-e-texinfo--find-verb-separator text)))
- (concat "@verb{" separator text separator "}")))
- ((eq 'code fmt)
- (let ((start 0)
- (rtn "")
- char)
- (while (string-match "[@{}]" text)
- (setq char (match-string 0 text))
- (if (> (match-beginning 0) 0)
- (setq rtn (concat rtn (substring text 0 (match-beginning 0)))))
- (setq text (substring text (1+ (match-beginning 0))))
- (setq char (concat "@" char)
- rtn (concat rtn char)))
- (setq text (concat rtn text)
- fmt "@code{%s}")
- (format fmt text)))
- ;; Else use format string.
- (t (format fmt text)))))
-
-;;; Headline sanitizing
-
-(defun org-e-texinfo--sanitize-headline (headline info)
- "Remove all formatting from the text of a headline for use in
- node and menu listing."
- (mapconcat 'identity
- (org-e-texinfo--sanitize-headline-contents headline info) " "))
-
-(defun org-e-texinfo--sanitize-headline-contents (headline info)
- "Retrieve the content of the headline.
-
-Any content that can contain further formatting is checked
-recursively, to ensure that nested content is also properly
-retrieved."
- (loop for contents in headline append
- (cond
- ;; already a string
- ((stringp contents)
- (list (replace-regexp-in-string " $" "" contents)))
- ;; Is exported as-is (value)
- ((org-element-map contents '(verbatim code)
- (lambda (value)
- (org-element-property :value value))))
- ;; Has content and recurse into the content
- ((org-element-contents contents)
- (org-e-texinfo--sanitize-headline-contents
- (org-element-contents contents) info)))))
-
-;;; Menu sanitizing
-
-(defun org-e-texinfo--sanitize-menu (title)
- "Remove invalid characters from TITLE for use in menus and
-nodes.
-
-Based on TEXINFO specifications, the following must be removed:
-@ { } ( ) : . ,"
- (replace-regexp-in-string "[@{}():,.]" "" title))
-
-;;; Content sanitizing
-
-(defun org-e-texinfo--sanitize-content (text)
- "Ensure characters are properly escaped when used in headlines or blocks.
-
-Escape characters are: @ { }"
- (replace-regexp-in-string "\\\([@{}]\\\)" "@\\1" text))
-
-;;; Menu creation
-
-(defun org-e-texinfo--build-menu (tree level info &optional detailed)
- "Create the @menu/@end menu information from TREE at headline
-level LEVEL.
-
-TREE contains the parse-tree to work with, either of the entire
-document or of a specific parent headline. LEVEL indicates what
-level of headlines to look at when generating the menu. INFO is
-a plist containing contextual information.
-
-Detailed determines whether to build a single level of menu, or
-recurse into all children as well."
- (let ((menu (org-e-texinfo--generate-menu-list tree level info))
- output text-menu)
- (cond
- (detailed
- ;; Looping is done within the menu generation.
- (setq text-menu (org-e-texinfo--generate-detailed menu level info)))
- (t
- (setq text-menu (org-e-texinfo--generate-menu-items menu info))))
- (when text-menu
- (setq output (org-e-texinfo--format-menu text-menu))
- (mapconcat 'identity output "\n"))))
-
-(defun org-e-texinfo--generate-detailed (menu level info)
- "Generate a detailed listing of all subheadings within MENU starting at LEVEL.
-
-MENU is the parse-tree to work with. LEVEL is the starting level
-for the menu headlines and from which recursion occurs. INFO is
-a plist containing contextual information."
- (when level
- (let ((max-depth (plist-get info :headline-levels)))
- (when (> max-depth level)
- (loop for headline in menu append
- (let* ((title (org-e-texinfo--menu-headlines headline info))
- ;; Create list of menu entries for the next level
- (sublist (org-e-texinfo--generate-menu-list
- headline (1+ level) info))
- ;; Generate the menu items for that level. If
- ;; there are none omit that heading completely,
- ;; otherwise join the title to it's related entries.
- (submenu (if (org-e-texinfo--generate-menu-items sublist info)
- (append (list title)
- (org-e-texinfo--generate-menu-items sublist info))
- 'nil))
- ;; Start the process over the next level down.
- (recursion (org-e-texinfo--generate-detailed sublist (1+ level) info)))
- (setq recursion (append submenu recursion))
- recursion))))))
-
-(defun org-e-texinfo--generate-menu-list (tree level info)
- "Generate the list of headlines that are within a given level
-of the tree for further formatting.
-
-TREE is the parse-tree containing the headlines. LEVEL is the
-headline level to generate a list of. INFO is a plist holding
-contextual information."
- (let (seq)
- (org-element-map
- tree 'headline
- (lambda (head)
- (when (org-element-property :level head)
- (if (and (eq level (org-element-property :level head))
- ;; Do not take note of footnotes or copying headlines
- (not (org-element-property :copying head))
- (not (org-element-property :footnote-section-p head)))
- (push head seq)))))
- ;; Return the list of headlines (reverse to have in actual order)
- (reverse seq)))
-
-(defun org-e-texinfo--generate-menu-items (items info)
- "Generate a list of headline information from the listing ITEMS.
-
-ITEMS is a list of the headlines to be converted into entries.
-INFO is a plist containing contextual information.
-
-Returns a list containing the following information from each
-headline: length, title, description. This is used to format the
-menu using `org-e-texinfo--format-menu'."
- (loop for headline in items collect
- (let* ((title (org-e-texinfo--sanitize-menu
- (org-e-texinfo--sanitize-headline
- (org-element-property :title headline) info)))
- (descr (org-export-data
- (org-element-property :description headline) info))
- (len (length title))
- (output (list len title descr)))
- output)))
-
-(defun org-e-texinfo--menu-headlines (headline info)
- "Retrieve the title from HEADLINE.
-
-INFO is a plist holding contextual information.
-
-Return the headline as a list of (length title description) with
-length of -1 and nil description. This is used in
-`org-e-texinfo--format-menu' to identify headlines as opposed to
-entries."
- (let ((title (org-export-data
- (org-element-property :title headline) info)))
- (list -1 title 'nil)))
-
-(defun org-e-texinfo--format-menu (text-menu)
- "Format the TEXT-MENU items to be properly printed in the menu.
-
-Each entry in the menu should be provided as (length title
-description).
-
-Headlines in the detailed menu are given length -1 to ensure they
-are never confused with other entries. They also have no
-description.
-
-Other menu items are output as:
- Title:: description
-
-With the spacing between :: and description based on the length
-of the longest menu entry."
-
- (let* ((lengths (mapcar 'car text-menu))
- (max-length (apply 'max lengths))
- output)
- (setq output
- (mapcar (lambda (name)
- (let* ((title (nth 1 name))
- (desc (nth 2 name))
- (length (nth 0 name)))
- (if (> length -1)
- (concat "* " title ":: "
- (make-string
- (- (+ 3 max-length) length)
- ?\s)
- (if desc
- (concat desc)))
- (concat "\n" title "\n"))))
- text-menu))
- output))
-
-;;; Template
-
-(defun org-e-texinfo-template (contents info)
- "Return complete document string after Texinfo conversion.
-CONTENTS is the transcoded contents string. INFO is a plist
-holding export options."
- (let* ((title (org-export-data (plist-get info :title) info))
- (info-filename (or (plist-get info :texinfo-filename)
- (file-name-nondirectory
- (org-export-output-file-name ".info"))))
- (author (org-export-data (plist-get info :author) info))
- (texinfo-header (plist-get info :texinfo-header))
- (subtitle (plist-get info :subtitle))
- (subauthor (plist-get info :subauthor))
- (class (plist-get info :texinfo-class))
- (header (nth 1 (assoc class org-e-texinfo-classes)))
- (copying (org-e-texinfo--find-copying info))
- (dircat (plist-get info :texinfo-dircat))
- (dirtitle (plist-get info :texinfo-dirtitle))
- (dirdesc (plist-get info :texinfo-dirdesc))
- ;; Spacing to align description (column 32 - 3 for `* ' and
- ;; `.' in text.
- (dirspacing (- 29 (length dirtitle)))
- (menu (org-e-texinfo-make-menu info 'main))
- (detail-menu (org-e-texinfo-make-menu info 'detailed)))
- (concat
- ;; Header
- header "\n"
- "@c %**start of header\n"
- ;; Filename and Title
- "@setfilename " info-filename "\n"
- "@settitle " title "\n"
- "\n\n"
- "@c Version and Contact Info\n"
- "@set AUTHOR " author "\n"
-
- ;; Additional Header Options set by `#+TEXINFO_HEADER
- (if texinfo-header
- (concat "\n"
- texinfo-header
- "\n"))
-
- "@c %**end of header\n"
- "@finalout\n"
- "\n\n"
-
- ;; Copying
- "@copying\n"
- ;; Only export the content of the headline, do not need the
- ;; initial headline.
- (org-export-data (nth 2 copying) info)
- "@end copying\n"
- "\n\n"
-
- ;; Info directory information
- ;; Only supply if both title and category are provided
- (if (and dircat dirtitle)
- (concat "@dircategory " dircat "\n"
- "@direntry\n"
- "* " dirtitle "."
- (make-string dirspacing ?\s)
- dirdesc "\n"
- "@end direntry\n"))
- "\n\n"
-
- ;; Title
- "@titlepage\n"
- "@title " title "\n\n"
- (if subtitle
- (concat "@subtitle " subtitle "\n"))
- "@author " author "\n"
- (if subauthor
- (concat subauthor "\n"))
- "\n"
- "@c The following two commands start the copyright page.\n"
- "@page\n"
- "@vskip 0pt plus 1filll\n"
- "@insertcopying\n"
- "@end titlepage\n\n"
- "@c Output the table of contents at the beginning.\n"
- "@contents\n\n"
-
- ;; Configure Top Node when not for Tex
- "@ifnottex\n"
- "@node Top\n"
- "@top " title " Manual\n"
- "@insertcopying\n"
- "@end ifnottex\n\n"
-
- ;; Do not output menus if they are empty
- (if menu
- ;; Menu
- (concat "@menu\n"
- menu
- "\n\n"
- ;; Detailed Menu
- (if detail-menu
- (concat "@detailmenu\n"
- " --- The Detailed Node Listing ---\n"
- detail-menu
- "\n\n"
- "@end detailmenu\n"))
- "@end menu\n"))
- "\n\n"
-
- ;; Document's body.
- contents
- "\n"
- ;; Creator.
- (let ((creator-info (plist-get info :with-creator)))
- (cond
- ((not creator-info) "")
- ((eq creator-info 'comment)
- (format "@c %s\n" (plist-get info :creator)))
- (t (concat (plist-get info :creator) "\n"))))
- ;; Document end.
- "\n@bye")))
-
-
-
-;;; Transcode Functions
-
-;;; Babel Call
-;;
-;; Babel Calls are ignored.
-
-;;; Bold
-
-(defun org-e-texinfo-bold (bold contents info)
- "Transcode BOLD from Org to Texinfo.
-CONTENTS is the text with bold markup. INFO is a plist holding
-contextual information."
- (org-e-texinfo--text-markup contents 'bold))
-
-;;; Center Block
-;;
-;; Center blocks are ignored
-
-;;; Clock
-
-(defun org-e-texinfo-clock (clock contents info)
- "Transcode a CLOCK element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (concat
- "@noindent"
- (format "@strong{%s} " org-clock-string)
- (format org-e-texinfo-inactive-timestamp-format
- (concat (org-translate-time (org-element-property :value clock))
- (let ((time (org-element-property :time clock)))
- (and time (format " (%s)" time)))))
- "@*"))
-
-;;; Code
-
-(defun org-e-texinfo-code (code contents info)
- "Transcode a CODE object from Org to Texinfo.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (org-e-texinfo--text-markup (org-element-property :value code) 'code))
-
-;;; Comment
-
-(defun org-e-texinfo-comment (comment contents info)
- "Transcode a COMMENT object from Org to Texinfo.
-CONTENTS is the text in the comment. INFO is a plist holding
-contextual information."
- (org-e-texinfo--text-markup (org-element-property :value comment) 'comment))
-
-;;; Comment Block
-
-(defun org-e-texinfo-comment-block (comment-block contents info)
- "Transcode a COMMENT-BLOCK object from Org to Texinfo.
-CONTENTS is the text within the block. INFO is a plist holding
-contextual information."
- (format "@ignore\n%s@end ignore" (org-element-property :value comment-block)))
-
-;;; Drawer
-
-(defun org-e-texinfo-drawer (drawer contents info)
- "Transcode a DRAWER element from Org to Texinfo.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let* ((name (org-element-property :drawer-name drawer))
- (output (if (functionp org-e-texinfo-format-drawer-function)
- (funcall org-e-texinfo-format-drawer-function
- name contents)
- ;; If there's no user defined function: simply
- ;; display contents of the drawer.
- contents)))
- output))
-
-;;; Dynamic Block
-
-(defun org-e-texinfo-dynamic-block (dynamic-block contents info)
- "Transcode a DYNAMIC-BLOCK element from Org to Texinfo.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information. See `org-export-data'."
- contents)
-
-;;; Entity
-
-(defun org-e-texinfo-entity (entity contents info)
- "Transcode an ENTITY object from Org to Texinfo.
-CONTENTS are the definition itself. INFO is a plist holding
-contextual information."
- (let ((ent (org-element-property :latex entity)))
- (if (org-element-property :latex-math-p entity) (format "@math{%s}" ent) ent)))
-
-;;; Example Block
-
-(defun org-e-texinfo-example-block (example-block contents info)
- "Transcode an EXAMPLE-BLOCK element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format "@verbatim\n%s@end verbatim"
- (org-export-format-code-default example-block info)))
-
-;;; Export Block
-
-(defun org-e-texinfo-export-block (export-block contents info)
- "Transcode a EXPORT-BLOCK element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (string= (org-element-property :type export-block) "TEXINFO")
- (org-remove-indentation (org-element-property :value export-block))))
-
-;;; Export Snippet
-
-(defun org-e-texinfo-export-snippet (export-snippet contents info)
- "Transcode a EXPORT-SNIPPET object from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (when (eq (org-export-snippet-backend export-snippet) 'e-texinfo)
- (org-element-property :value export-snippet)))
-
-;;; Fixed Width
-
-(defun org-e-texinfo-fixed-width (fixed-width contents info)
- "Transcode a FIXED-WIDTH element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (format "@example\n%s\n@end example"
- (org-remove-indentation
- (org-e-texinfo--sanitize-content
- (org-element-property :value fixed-width)))))
-
-;;; Footnote Definition
-;;
-;; Footnote Definitions are ignored.
-
-;;; Footnote Reference
-;;
-
-(defun org-e-texinfo-footnote-reference (footnote contents info)
- "Create a footnote reference for FOOTNOTE.
-
-FOOTNOTE is the footnote to define. CONTENTS is nil. INFO is a
-plist holding contextual information."
- (let ((def (org-export-get-footnote-definition footnote info)))
- (format "@footnote{%s}"
- (org-trim (org-export-data def info)))))
-
-;;; Headline
-
-(defun org-e-texinfo-headline (headline contents info)
- "Transcode an HEADLINE element from Org to Texinfo.
-CONTENTS holds the contents of the headline. INFO is a plist
-holding contextual information."
- (let* ((class (plist-get info :texinfo-class))
- (level (org-export-get-relative-level headline info))
- (numberedp (org-export-numbered-headline-p headline info))
- (class-sectionning (assoc class org-e-texinfo-classes))
- ;; Find the index type, if any
- (index (org-element-property :index headline))
- ;; Retrieve headline text
- (text (org-e-texinfo--sanitize-headline
- (org-element-property :title headline) info))
- ;; Create node info, to insert it before section formatting.
- (node (format "@node %s\n"
- (org-e-texinfo--sanitize-menu
- (replace-regexp-in-string "%" "%%" text))))
- ;; Menus must be generated with first child, otherwise they
- ;; will not nest properly
- (menu (let* ((first (org-export-first-sibling-p headline info))
- (parent (org-export-get-parent-headline headline))
- (title (org-e-texinfo--sanitize-headline
- (org-element-property :title parent) info))
- heading listing
- (tree (plist-get info :parse-tree)))
- (if first
- (org-element-map
- (plist-get info :parse-tree) 'headline
- (lambda (ref)
- (if (member title (org-element-property :title ref))
- (push ref heading)))
- info 't))
- (setq listing (org-e-texinfo--build-menu
- (car heading) level info))
- (if listing
- (setq listing (replace-regexp-in-string
- "%" "%%" listing)
- listing (format
- "\n@menu\n%s\n@end menu\n\n" listing))
- 'nil)))
- ;; Section formatting will set two placeholders: one for the
- ;; title and the other for the contents.
- (section-fmt
- (let ((sec (if (and (symbolp (nth 2 class-sectionning))
- (fboundp (nth 2 class-sectionning)))
- (funcall (nth 2 class-sectionning) level numberedp)
- (nth (1+ level) class-sectionning))))
- (cond
- ;; No section available for that LEVEL.
- ((not sec) nil)
- ;; Section format directly returned by a function.
- ((stringp sec) sec)
- ;; (numbered-section . unnumbered-section)
- ((not (consp (cdr sec)))
- ;; If an index, always unnumbered
- (if index
- (concat menu node (cdr sec) "\n%s")
- ;; Otherwise number as needed.
- (concat menu node
- (funcall
- (if numberedp #'car #'cdr) sec) "\n%s"))))))
- (todo
- (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword headline)))
- (and todo (org-export-data todo info)))))
- (todo-type (and todo (org-element-property :todo-type headline)))
- (tags (and (plist-get info :with-tags)
- (org-export-get-tags headline info)))
- (priority (and (plist-get info :with-priority)
- (org-element-property :priority headline)))
- ;; Create the headline text along with a no-tag version. The
- ;; latter is required to remove tags from table of contents.
- (full-text (org-e-texinfo--sanitize-content
- (if (functionp org-e-texinfo-format-headline-function)
- ;; User-defined formatting function.
- (funcall org-e-texinfo-format-headline-function
- todo todo-type priority text tags)
- ;; Default formatting.
- (concat
- (when todo
- (format "@strong{%s} " todo))
- (when priority (format "@emph{#%s} " priority))
- text
- (when tags
- (format ":%s:"
- (mapconcat 'identity tags ":")))))))
- (full-text-no-tag
- (org-e-texinfo--sanitize-content
- (if (functionp org-e-texinfo-format-headline-function)
- ;; User-defined formatting function.
- (funcall org-e-texinfo-format-headline-function
- todo todo-type priority text nil)
- ;; Default formatting.
- (concat
- (when todo (format "@strong{%s} " todo))
- (when priority (format "@emph{#%c} " priority))
- text))))
- (pre-blanks
- (make-string (org-element-property :pre-blank headline) 10)))
- (cond
- ;; Case 1: This is a footnote section: ignore it.
- ((org-element-property :footnote-section-p headline) nil)
- ;; Case 2: This is the `copying' section: ignore it
- ;; This is used elsewhere.
- ((org-element-property :copying headline) nil)
- ;; Case 3: An index. If it matches one of the known indexes,
- ;; print it as such following the contents, otherwise
- ;; print the contents and leave the index up to the user.
- (index
- (format
- section-fmt full-text
- (concat pre-blanks contents "\n"
- (if (member index '("cp" "fn" "ky" "pg" "tp" "vr"))
- (concat "@printindex " index)))))
- ;; Case 4: This is a deep sub-tree: export it as a list item.
- ;; Also export as items headlines for which no section
- ;; format has been found.
- ((or (not section-fmt) (org-export-low-level-p headline info))
- ;; Build the real contents of the sub-tree.
- (let ((low-level-body
- (concat
- ;; If the headline is the first sibling, start a list.
- (when (org-export-first-sibling-p headline info)
- (format "@%s\n" (if numberedp 'enumerate 'itemize)))
- ;; Itemize headline
- "@item\n" full-text "\n" pre-blanks contents)))
- ;; If headline is not the last sibling simply return
- ;; LOW-LEVEL-BODY. Otherwise, also close the list, before any
- ;; blank line.
- (if (not (org-export-last-sibling-p headline info)) low-level-body
- (replace-regexp-in-string
- "[ \t\n]*\\'"
- (format "\n@end %s" (if numberedp 'enumerate 'itemize))
- low-level-body))))
- ;; Case 5: Standard headline. Export it as a section.
- (t
- (cond
- ((not (and tags (eq (plist-get info :with-tags) 'not-in-toc)))
- ;; Regular section. Use specified format string.
- (format (replace-regexp-in-string "%]" "%%]" section-fmt) full-text
- (concat pre-blanks contents)))
- ((string-match "\\`@\\(.*?\\){" section-fmt)
- ;; If tags should be removed from table of contents, insert
- ;; title without tags as an alternative heading in sectioning
- ;; command.
- (format (replace-match (concat (match-string 1 section-fmt) "[%s]")
- nil nil section-fmt 1)
- ;; Replace square brackets with parenthesis since
- ;; square brackets are not supported in optional
- ;; arguments.
- (replace-regexp-in-string
- "\\[" "("
- (replace-regexp-in-string
- "\\]" ")"
- full-text-no-tag))
- full-text
- (concat pre-blanks contents)))
- (t
- ;; Impossible to add an alternative heading. Fallback to
- ;; regular sectioning format string.
- (format (replace-regexp-in-string "%]" "%%]" section-fmt) full-text
- (concat pre-blanks contents))))))))
-
-;;; Horizontal Rule
-;;
-;; Horizontal rules are ignored
-
-;;; Inline Babel Call
-;;
-;; Inline Babel Calls are ignored.
-
-;;; Inline Src Block
-
-(defun org-e-texinfo-inline-src-block (inline-src-block contents info)
- "Transcode an INLINE-SRC-BLOCK element from Org to Texinfo.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((code (org-element-property :value inline-src-block))
- (separator (org-e-texinfo--find-verb-separator code)))
- (concat "@verb{" separator code separator "}")))
-
-;;; Inlinetask
-
-(defun org-e-texinfo-inlinetask (inlinetask contents info)
- "Transcode an INLINETASK element from Org to Texinfo.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let ((title (org-export-data (org-element-property :title inlinetask) info))
- (todo (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword inlinetask)))
- (and todo (org-export-data todo info)))))
- (todo-type (org-element-property :todo-type inlinetask))
- (tags (and (plist-get info :with-tags)
- (org-export-get-tags inlinetask info)))
- (priority (and (plist-get info :with-priority)
- (org-element-property :priority inlinetask))))
- ;; If `org-e-texinfo-format-inlinetask-function' is provided, call it
- ;; with appropriate arguments.
- (if (functionp org-e-texinfo-format-inlinetask-function)
- (funcall org-e-texinfo-format-inlinetask-function
- todo todo-type priority title tags contents)
- ;; Otherwise, use a default template.
- (let ((full-title
- (concat
- (when todo (format "@strong{%s} " todo))
- (when priority (format "#%c " priority))
- title
- (when tags (format ":%s:"
- (mapconcat 'identity tags ":"))))))
- (format (concat "@center %s\n\n"
- "%s"
- "\n")
- full-title contents)))))
-
-;;; Italic
-
-(defun org-e-texinfo-italic (italic contents info)
- "Transcode ITALIC from Org to Texinfo.
-CONTENTS is the text with italic markup. INFO is a plist holding
-contextual information."
- (org-e-texinfo--text-markup contents 'italic))
-
-;;; Item
-
-(defun org-e-texinfo-item (item contents info)
- "Transcode an ITEM element from Org to Texinfo.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((tag (org-element-property :tag item))
- (desc (org-export-data tag info)))
- (concat "\n@item " (if tag desc) "\n"
- (org-trim contents) "\n")))
-
-;;; Keyword
-
-(defun org-e-texinfo-keyword (keyword contents info)
- "Transcode a KEYWORD element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((key (org-element-property :key keyword))
- (value (org-element-property :value keyword)))
- (cond
- ((string= key "TEXINFO") value)
- ((string= key "CINDEX") (format "@cindex %s" value))
- ((string= key "FINDEX") (format "@findex %s" value))
- ((string= key "KINDEX") (format "@kindex %s" value))
- ((string= key "PINDEX") (format "@pindex %s" value))
- ((string= key "TINDEX") (format "@tindex %s" value))
- ((string= key "VINDEX") (format "@vindex %s" value)))))
-
-;;; Latex Environment
-;;
-;; Latex environments are ignored
-
-;;; Latex Fragment
-;;
-;; Latex fragments are ignored.
-
-;;; Line Break
-
-(defun org-e-texinfo-line-break (line-break contents info)
- "Transcode a LINE-BREAK object from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- "@*")
-
-;;; Link
-
-(defun org-e-texinfo-link (link desc info)
- "Transcode a LINK object from Org to Texinfo.
-
-DESC is the description part of the link, or the empty string.
-INFO is a plist holding contextual information. See
-`org-export-data'."
- (let* ((type (org-element-property :type link))
- (raw-path (org-element-property :path link))
- ;; Ensure DESC really exists, or set it to nil.
- (desc (and (not (string= desc "")) desc))
- (path (cond
- ((member type '("http" "https" "ftp"))
- (concat type ":" raw-path))
- ((string= type "file")
- (when (string-match "\\(.+\\)::.+" raw-path)
- (setq raw-path (match-string 1 raw-path)))
- (if (file-name-absolute-p raw-path)
- (concat "file://" (expand-file-name raw-path))
- (concat "file://" raw-path)))
- (t raw-path)))
- (email (if (string= type "mailto")
- (let ((text (replace-regexp-in-string
- "@" "@@" raw-path)))
- (concat text (if desc (concat "," desc))))))
- protocol)
- (cond
- ;; Links pointing to an headline: Find destination and build
- ;; appropriate referencing command.
- ((member type '("custom-id" "id"))
- (let ((destination (org-export-resolve-id-link link info)))
- (case (org-element-type destination)
- ;; Id link points to an external file.
- (plain-text
- (if desc (format "@uref{file://%s,%s}" destination desc)
- (format "@uref{file://%s}" destination)))
- ;; LINK points to an headline. Use the headline as the NODE target
- (headline
- (format "@ref{%s}"
- (org-export-data
- (org-element-property :title destination) info)))
- (otherwise
- (let ((path (org-export-solidify-link-text path)))
- (if (not desc) (format "@ref{%s}" path)
- (format "@ref{%s,,%s}" path desc)))))))
- ((member type '("fuzzy"))
- (let ((destination (org-export-resolve-fuzzy-link link info)))
- (case (org-element-type destination)
- ;; Id link points to an external file.
- (plain-text
- (if desc (format "@uref{file://%s,%s}" destination desc)
- (format "@uref{file://%s}" destination)))
- ;; LINK points to an headline. Use the headline as the NODE target
- (headline
- (format "@ref{%s}"
- (org-export-data
- (org-element-property :title destination) info)))
- (otherwise
- (let ((path (org-export-solidify-link-text path)))
- (if (not desc) (format "@ref{%s}" path)
- (format "@ref{%s,,%s}" path desc)))))))
- ;; Special case for email addresses
- (email
- (format "@email{%s}" email))
- ;; External link with a description part.
- ((and path desc) (format "@uref{%s,%s}" path desc))
- ;; External link without a description part.
- (path (format "@uref{%s}" path))
- ;; No path, only description. Try to do something useful.
- (t (format org-e-texinfo-link-with-unknown-path-format desc)))))
-
-;;; Macro
-
-(defun org-e-texinfo-macro (macro contents info)
- "Transcode a MACRO element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- ;; Use available tools.
- (org-export-expand-macro macro info))
-
-;;; Menu
-
-(defun org-e-texinfo-make-menu (info level)
- "Create the menu for inclusion in the texifo document.
-
-INFO is the parsed buffer that contains the headlines. LEVEL
-determines whether to make the main menu, or the detailed menu.
-
-This is only used for generating the primary menu. In-Node menus
-are generated directly."
- (let* ((parse (plist-get info :parse-tree))
- ;; Top determines level to build menu from, it finds the
- ;; level of the first headline in the export.
- (top (org-element-map
- parse 'headline
- (lambda (headline)
- (org-element-property :level headline)) info 't)))
- (cond
- ;; Generate the main menu
- ((eq level 'main)
- (org-e-texinfo--build-menu parse top info))
- ;; Generate the detailed (recursive) menu
- ((eq level 'detailed)
- ;; Requires recursion
- ;;(org-e-texinfo--build-detailed-menu parse top info)
- (org-e-texinfo--build-menu parse top info 'detailed))
- ;; Otherwise do nothing
- (t))))
-
-;;; Paragraph
-
-(defun org-e-texinfo-paragraph (paragraph contents info)
- "Transcode a PARAGRAPH element from Org to Texinfo.
-CONTENTS is the contents of the paragraph, as a string. INFO is
-the plist used as a communication channel."
- contents)
-
-;;; Plain List
-
-(defun org-e-texinfo-plain-list (plain-list contents info)
- "Transcode a PLAIN-LIST element from Org to Texinfo.
-CONTENTS is the contents of the list. INFO is a plist holding
-contextual information."
- (let* ((attr (org-export-read-attribute :attr_texinfo plain-list))
- (indic (or (plist-get attr :indic)
- org-e-texinfo-def-table-markup))
- (type (org-element-property :type plain-list))
- (table-type (or (plist-get attr :table-type)
- "table"))
- ;; Ensure valid texinfo table type.
- (table-type (if (memq table-type '("table" "ftable" "vtable"))
- table-type
- "table"))
- (list-type (cond
- ((eq type 'ordered) "enumerate")
- ((eq type 'unordered) "itemize")
- ((eq type 'descriptive) table-type))))
- (format "@%s%s\n@end %s"
- (if (eq type 'descriptive)
- (concat list-type " " indic)
- list-type)
- contents
- list-type)))
-
-;;; Plain Text
-
-(defun org-e-texinfo-plain-text (text info)
- "Transcode a TEXT string from Org to Texinfo.
-TEXT is the string to transcode. INFO is a plist holding
-contextual information."
- ;; LaTeX into @LaTeX{} and TeX into @TeX{}
- (let ((case-fold-search nil)
- (start 0))
- (while (string-match "\\(\\(?:La\\)?TeX\\)" text start)
- (setq text (replace-match
- (format "@%s{}" (match-string 1 text)) nil t text)
- start (match-end 0))))
- ;; Handle quotation marks
- (setq text (org-e-texinfo--quotation-marks text info))
- ;; Convert special strings.
- (when (plist-get info :with-special-strings)
- (while (string-match (regexp-quote "...") text)
- (setq text (replace-match "@dots{}" nil t text))))
- ;; Handle break preservation if required.
- (when (plist-get info :preserve-breaks)
- (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " @*\n"
- text)))
- ;; Return value with @ { and } protected.
- (org-e-texinfo--sanitize-content text))
-
-;;; Planning
-
-(defun org-e-texinfo-planning (planning contents info)
- "Transcode a PLANNING element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (concat
- "@noindent"
- (mapconcat
- 'identity
- (delq nil
- (list
- (let ((closed (org-element-property :closed planning)))
- (when closed
- (concat
- (format "@strong%s} " org-closed-string)
- (format org-e-texinfo-inactive-timestamp-format
- (org-translate-time closed)))))
- (let ((deadline (org-element-property :deadline planning)))
- (when deadline
- (concat
- (format "@strong{%s} " org-deadline-string)
- (format org-e-texinfo-active-timestamp-format
- (org-translate-time deadline)))))
- (let ((scheduled (org-element-property :scheduled planning)))
- (when scheduled
- (concat
- (format "@strong{%s} " org-scheduled-string)
- (format org-e-texinfo-active-timestamp-format
- (org-translate-time scheduled)))))))
- " ")
- "@*"))
-
-;;; Property Drawer
-
-(defun org-e-texinfo-property-drawer (property-drawer contents info)
- "Transcode a PROPERTY-DRAWER element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- ;; The property drawer isn't exported but we want separating blank
- ;; lines nonetheless.
- "")
-
-;;; Quote Block
-
-(defun org-e-texinfo-quote-block (quote-block contents info)
- "Transcode a QUOTE-BLOCK element from Org to Texinfo.
-CONTENTS holds the contents of the block. INFO is a plist
-holding contextual information."
- (let* ((title (org-element-property :name quote-block))
- (start-quote (concat "@quotation"
- (if title
- (format " %s" title)))))
- (format "%s\n%s@end quotation" start-quote contents)))
-
-;;; Quote Section
-
-(defun org-e-texinfo-quote-section (quote-section contents info)
- "Transcode a QUOTE-SECTION element from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((value (org-remove-indentation
- (org-element-property :value quote-section))))
- (when value (format "@verbatim\n%s@end verbatim" value))))
-
-;;; Radio Target
-
-(defun org-e-texinfo-radio-target (radio-target text info)
- "Transcode a RADIO-TARGET object from Org to Texinfo.
-TEXT is the text of the target. INFO is a plist holding
-contextual information."
- (format "@anchor{%s}%s"
- (org-export-solidify-link-text
- (org-element-property :value radio-target))
- text))
-
-;;; Section
-
-(defun org-e-texinfo-section (section contents info)
- "Transcode a SECTION element from Org to Texinfo.
-CONTENTS holds the contents of the section. INFO is a plist
-holding contextual information."
- contents)
-
-;;; Special Block
-;;
-;; Are ignored at the moment
-
-;;; Src Block
-
-(defun org-e-texinfo-src-block (src-block contents info)
- "Transcode a SRC-BLOCK element from Org to Texinfo.
-CONTENTS holds the contents of the item. INFO is a plist holding
-contextual information."
- (let* ((lang (org-element-property :language src-block))
- (lisp-p (string-match-p "lisp" lang)))
- (cond
- ;; Case 1. Lisp Block
- (lisp-p
- (format "@lisp\n%s\n@end lisp"
- (org-export-format-code-default src-block info)))
- ;; Case 2. Other blocks
- (t
- (format "@example\n%s\n@end example"
- (org-export-format-code-default src-block info))))))
-
-;;; Statistics Cookie
-
-(defun org-e-texinfo-statistics-cookie (statistics-cookie contents info)
- "Transcode a STATISTICS-COOKIE object from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-element-property :value statistics-cookie))
-
-;;; Strike-Through
-;;
-;; Strikethrough is ignored
-
-;;; Subscript
-
-(defun org-e-texinfo-subscript (subscript contents info)
- "Transcode a SUBSCRIPT object from Org to Texinfo.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "@math{_%s}" contents))
-
-;;; Superscript
-
-(defun org-e-texinfo-superscript (superscript contents info)
- "Transcode a SUPERSCRIPT object from Org to Texinfo.
-CONTENTS is the contents of the object. INFO is a plist holding
-contextual information."
- (format "@math{^%s}" contents))
-
-;;; Table
-;;
-;; `org-e-texinfo-table' is the entry point for table transcoding. It
-;; takes care of tables with a "verbatim" attribute. Otherwise, it
-;; delegates the job to either `org-e-texinfo-table--table.el-table' or
-;; `org-e-texinfo-table--org-table' functions, depending of the type of
-;; the table.
-;;
-;; `org-e-texinfo-table--align-string' is a subroutine used to build
-;; alignment string for Org tables.
-
-(defun org-e-texinfo-table (table contents info)
- "Transcode a TABLE element from Org to Texinfo.
-CONTENTS is the contents of the table. INFO is a plist holding
-contextual information."
- (cond
- ;; Case 1: verbatim table.
- ((or org-e-texinfo-tables-verbatim
- (let ((attr (mapconcat 'identity
- (org-element-property :attr_latex table)
- " ")))
- (and attr (string-match "\\<verbatim\\>" attr))))
- (format "@verbatim \n%s\n@end verbatim"
- ;; Re-create table, without affiliated keywords.
- (org-trim
- (org-element-interpret-data
- `(table nil ,@(org-element-contents table))))))
- ;; Case 2: table.el table. Convert it using appropriate tools.
- ((eq (org-element-property :type table) 'table.el)
- (org-e-texinfo-table--table.el-table table contents info))
- ;; Case 3: Standard table.
- (t (org-e-texinfo-table--org-table table contents info))))
-
-(defun org-e-texinfo-table-column-widths (table info)
- "Determine the largest table cell in each column to process alignment.
-
-TABLE is the table element to transcode. INFO is a plist used as
-a communication channel."
- (let* ((rows (org-element-map table 'table-row 'identity info))
- (collected (loop for row in rows collect
- (org-element-map
- row 'table-cell 'identity info)))
- (number-cells (length (car collected)))
- cells counts)
- (loop for row in collected do
- (push (mapcar (lambda (ref)
- (let* ((start (org-element-property :contents-begin ref))
- (end (org-element-property :contents-end ref))
- (length (- end start)))
- length)) row) cells))
- (setq cells (remove-if #'null cells))
- (push (loop for count from 0 to (- number-cells 1) collect
- (loop for item in cells collect
- (nth count item))) counts)
- (mapconcat (lambda (size)
- (make-string size ?a)) (mapcar (lambda (ref)
- (apply 'max `,@ref)) (car counts))
- "} {")))
-
-(defun org-e-texinfo-table--org-table (table contents info)
- "Return appropriate Texinfo code for an Org table.
-
-TABLE is the table type element to transcode. CONTENTS is its
-contents, as a string. INFO is a plist used as a communication
-channel.
-
-This function assumes TABLE has `org' as its `:type' attribute."
- (let* ((attr (org-export-read-attribute :attr_texinfo table))
- (col-width (plist-get attr :columns))
- (columns (if col-width
- (format "@columnfractions %s"
- col-width)
- (format "{%s}"
- (org-e-texinfo-table-column-widths
- table info)))))
- ;; Prepare the final format string for the table.
- (cond
- ;; Longtable.
- ;; Others.
- (t (concat
- (format "@multitable %s\n%s@end multitable"
- columns
- contents))))))
-
-(defun org-e-texinfo-table--table.el-table (table contents info)
- "Returns nothing.
-
-Rather than return an invalid table, nothing is returned."
- 'nil)
-
-;;; Table Cell
-
-(defun org-e-texinfo-table-cell (table-cell contents info)
- "Transcode a TABLE-CELL element from Org to Texinfo.
-CONTENTS is the cell contents. INFO is a plist used as
-a communication channel."
- (concat (if (and contents
- org-e-texinfo-table-scientific-notation
- (string-match orgtbl-exp-regexp contents))
- ;; Use appropriate format string for scientific
- ;; notation.
- (format org-e-texinfo-table-scientific-notation
- (match-string 1 contents)
- (match-string 2 contents))
- contents)
- (when (org-export-get-next-element table-cell info) "\n@tab ")))
-
-;;; Table Row
-
-(defun org-e-texinfo-table-row (table-row contents info)
- "Transcode a TABLE-ROW element from Org to Texinfo.
-CONTENTS is the contents of the row. INFO is a plist used as
-a communication channel."
- ;; Rules are ignored since table separators are deduced from
- ;; borders of the current row.
- (when (eq (org-element-property :type table-row) 'standard)
- (concat "@item " contents "\n")))
-
-;;; Target
-
-(defun org-e-texinfo-target (target contents info)
- "Transcode a TARGET object from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (format "@anchor{%s}"
- (org-export-solidify-link-text (org-element-property :value target))))
-
-;;; Timestamp
-
-(defun org-e-texinfo-timestamp (timestamp contents info)
- "Transcode a TIMESTAMP object from Org to Texinfo.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- (let ((value (org-translate-time (org-element-property :value timestamp)))
- (type (org-element-property :type timestamp)))
- (cond ((memq type '(active active-range))
- (format org-e-texinfo-active-timestamp-format value))
- ((memq type '(inactive inactive-range))
- (format org-e-texinfo-inactive-timestamp-format value))
- (t (format org-e-texinfo-diary-timestamp-format value)))))
-
-;;; Underline
-;;
-;; Underline is ignored
-
-;;; Verbatim
-
-(defun org-e-texinfo-verbatim (verbatim contents info)
- "Transcode a VERBATIM object from Org to Texinfo.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (org-e-texinfo--text-markup (org-element-property :value verbatim) 'verbatim))
-
-;;; Verse Block
-
-(defun org-e-texinfo-verse-block (verse-block contents info)
- "Transcode a VERSE-BLOCK element from Org to Texinfo.
-CONTENTS is verse block contents. INFO is a plist holding
-contextual information."
- ;; In a verse environment, add a line break to each newline
- ;; character and change each white space at beginning of a line
- ;; into a space of 1 em. Also change each blank line with
- ;; a vertical space of 1 em.
- (progn
- (setq contents (replace-regexp-in-string
- "^ *\\\\\\\\$" "\\\\vspace*{1em}"
- (replace-regexp-in-string
- "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n" contents)))
- (while (string-match "^[ \t]+" contents)
- (let ((new-str (format "\\hspace*{%dem}"
- (length (match-string 0 contents)))))
- (setq contents (replace-match new-str nil t contents))))
- (format "\\begin{verse}\n%s\\end{verse}" contents)))
-
-
-;;; Interactive functions
-
-(defun org-e-texinfo-export-to-texinfo
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to a Texinfo file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (let ((outfile (org-export-output-file-name ".texi" subtreep pub-dir)))
- (org-export-to-file
- 'e-texinfo outfile subtreep visible-only body-only ext-plist)))
-
-(defun org-e-texinfo-export-to-info
- (&optional subtreep visible-only body-only ext-plist pub-dir)
- "Export current buffer to Texinfo then process through to INFO.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 write code
-between \"\\begin{document}\" and \"\\end{document}\".
-
-EXT-PLIST, when provided, is a property list with external
-parameters overriding Org default settings, but still inferior to
-file-local settings.
-
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
-Return INFO file's name."
- (interactive)
- (org-e-texinfo-compile
- (org-e-texinfo-export-to-texinfo
- subtreep visible-only body-only ext-plist pub-dir)))
-
-(defun org-e-texinfo-compile (texifile)
- "Compile a texinfo file.
-
-TEXIFILE is the name of the file being compiled. Processing is
-done through the command specified in `org-e-texinfo-info-process'.
-
-Return INFO file name or an error if it couldn't be produced."
- (let* ((wconfig (current-window-configuration))
- (texifile (file-truename texifile))
- (base (file-name-sans-extension texifile))
- errors)
- (message (format "Processing Texinfo file %s ..." texifile))
- (unwind-protect
- (progn
- (cond
- ;; A function is provided: Apply it.
- ((functionp org-e-texinfo-info-process)
- (funcall org-e-texinfo-info-process (shell-quote-argument texifile)))
- ;; A list is provided: Replace %b, %f and %o with appropriate
- ;; values in each command before applying it. Output is
- ;; redirected to "*Org INFO Texinfo Output*" buffer.
- ((consp org-e-texinfo-info-process)
- (let* ((out-dir (or (file-name-directory texifile) "./"))
- (outbuf (get-buffer-create "*Org Info Texinfo Output*")))
- (mapc
- (lambda (command)
- (shell-command
- (replace-regexp-in-string
- "%b" (shell-quote-argument base)
- (replace-regexp-in-string
- "%f" (shell-quote-argument texifile)
- (replace-regexp-in-string
- "%o" (shell-quote-argument out-dir) command t t) t t) t t)
- outbuf))
- org-e-texinfo-info-process)
- ;; Collect standard errors from output buffer.
- (setq errors (org-e-texinfo-collect-errors outbuf))))
- (t (error "No valid command to process to Info")))
- (let ((infofile (concat base ".info")))
- ;; Check for process failure. Provide collected errors if
- ;; possible.
- (if (not (file-exists-p infofile))
- (error (concat (format "INFO file %s wasn't produced" infofile)
- (when errors (concat ": " errors))))
- ;; Else remove log files, when specified, and signal end of
- ;; process to user, along with any error encountered.
- (message (concat "Process completed"
- (if (not errors) "."
- (concat " with errors: " errors)))))
- ;; Return output file name.
- infofile))
- (set-window-configuration wconfig))))
-
-(defun org-e-texinfo-collect-errors (buffer)
- "Collect some kind of errors from \"makeinfo\" command output.
-
-BUFFER is the buffer containing output.
-
-Return collected error types as a string, or nil if there was
-none."
- (with-current-buffer buffer
- (save-excursion
- (goto-char (point-min))
- ;; Find final "makeinfo" run.
- (when t
- (let ((case-fold-search t)
- (errors ""))
- (when (save-excursion
- (re-search-forward "perhaps incorrect sectioning?" nil t))
- (setq errors (concat errors " [incorrect sectionnng]")))
- (when (save-excursion
- (re-search-forward "missing close brace" nil t))
- (setq errors (concat errors " [syntax error]")))
- (when (save-excursion
- (re-search-forward "Unknown command" nil t))
- (setq errors (concat errors " [undefined @command]")))
- (when (save-excursion
- (re-search-forward "No matching @end" nil t))
- (setq errors (concat errors " [block incomplete]")))
- (when (save-excursion
- (re-search-forward "requires a sectioning" nil t))
- (setq errors (concat errors " [invalid section command]")))
- (when (save-excursion
- (re-search-forward "\\[unexpected\]" nil t))
- (setq errors (concat errors " [unexpected error]")))
- (when (save-excursion
- (re-search-forward "misplaced " nil t))
- (setq errors (concat errors " [syntax error]")))
- (and (org-string-nw-p errors) (org-trim errors)))))))
-
-(provide 'org-e-texinfo)
-;;; org-e-texinfo.el ends here
diff --git a/contrib/lisp/org-elisp-symbol.el b/contrib/lisp/org-elisp-symbol.el
index 96b0e5d..e0bc284 100644
--- a/contrib/lisp/org-elisp-symbol.el
+++ b/contrib/lisp/org-elisp-symbol.el
@@ -1,8 +1,8 @@
;;; org-elisp-symbol.el --- Org links to emacs-lisp symbols
;;
-;; Copyright 2007-2012 Free Software Foundation, Inc.
+;; Copyright 2007-2013 Free Software Foundation, Inc.
;;
-;; Author: bzg AT gnu DOT org
+;; Author: Bastien Guerry
;; Version: 0.2
;; Keywords: org, remember, lisp
;; URL: http://www.cognition.ens.fr/~guerry/u/org-elisp-symbol.el
@@ -20,8 +20,7 @@
;; 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, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
diff --git a/contrib/lisp/org-eval-light.el b/contrib/lisp/org-eval-light.el
index 36f3c6d..34a2e99 100644
--- a/contrib/lisp/org-eval-light.el
+++ b/contrib/lisp/org-eval-light.el
@@ -1,6 +1,6 @@
;;; org-eval-light.el --- Display result of evaluating code in various languages (light)
-;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
;; Author: Carsten Dominik <carsten at orgmode dot org>,
;; Eric Schulte <schulte dot eric at gmail dot com>
@@ -11,20 +11,18 @@
;; This file is not yet part of GNU Emacs.
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/contrib/lisp/org-eval.el b/contrib/lisp/org-eval.el
index 9968669..6cd7f78 100644
--- a/contrib/lisp/org-eval.el
+++ b/contrib/lisp/org-eval.el
@@ -1,5 +1,5 @@
;;; org-eval.el --- Display result of evaluating code in various languages
-;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
;;
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -8,20 +8,18 @@
;;
;; This file is not yet part of GNU Emacs.
;;
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
@@ -88,8 +86,7 @@
(:foreground "yellow"))))
"Face for command output that is included into an Org-mode buffer."
:group 'org-eval
- :group 'org-faces
- :version "22.1")
+ :group 'org-faces)
(defvar org-eval-regexp nil)
diff --git a/contrib/lisp/org-exp-bibtex.el b/contrib/lisp/org-exp-bibtex.el
deleted file mode 100644
index 8a99243..0000000
--- a/contrib/lisp/org-exp-bibtex.el
+++ /dev/null
@@ -1,148 +0,0 @@
-;;; org-exp-bibtex.el --- Export bibtex fragments
-
-;; Copyright (C) 2009-2012 Taru Karttunen
-
-;; Author: Taru Karttunen <taruti@taruti.net>
-
-;; This file is not currently part of GNU Emacs.
-
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2, 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 ; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-;;
-;; This is an utility to handle BibTeX export to both LaTeX and html
-;; exports. It uses the bibtex2html software from
-;; http://www.lri.fr/~filliatr/bibtex2html/
-;;
-;; The usage is as follows:
-;; #+BIBLIOGRAPHY: bibfilebasename stylename optional-options
-;; e.g. given foo.bib and using style plain:
-;; #+BIBLIOGRAPHY: foo plain option:-d
-;;
-;; Optional options are of the form:
-;;
-;; option:-foobar pass '-foobar' to bibtex2html
-;; e.g.
-;; option:-d sort by date.
-;; option:-a sort as BibTeX (usually by author) *default*
-;; option:-u unsorted i.e. same order as in .bib file
-;; option:-r reverse the sort.
-;; see the bibtex2html man page for more. Multiple options can be combined like:
-;; option:-d option:-r
-;;
-;; Limiting to only the entries cited in the document:
-;; limit:t
-
-;; For LaTeX export this simply inserts the lines
-;; \bibliographystyle{plain}
-;; \bibliography{foo}
-;; into the tex-file when exporting.
-
-;; For Html export it:
-;; 1) converts all \cite{foo} to links to the bibliography
-;; 2) creates a foo.html and foo_bib.html
-;; 3) includes the contents of foo.html in the exported html file
-
-(require 'org)
-(require 'org-exp)
-
-(defvar org-export-current-backend) ; dynamically bound in org-exp.el
-(defun org-export-bibtex-preprocess ()
- "Export all BibTeX."
- (interactive)
- (save-window-excursion
- (setq oebp-cite-plist '())
-
- ;; Convert #+BIBLIOGRAPHY: name style
- (goto-char (point-min))
- (while (re-search-forward "^#\\+BIBLIOGRAPHY:[ \t]+\\(\\S-+\\)[ \t]+\\(\\S-+\\)\\([^\r\n]*\\)" nil t)
- (let ((file (match-string 1))
- (style (match-string 2))
- (opt (org-exp-bibtex-options-to-plist (match-string 3))))
- (replace-match
- (cond
- ((eq org-export-current-backend 'html) ;; We are exporting to HTML
- (let (extra-args cite-list end-hook tmp-files)
- (dolist (elt opt)
- (when (equal "option" (car elt))
- (setq extra-args (cons (cdr elt) extra-args))))
-
- (when (assoc "limit" opt) ;; Limit is true - collect references
- (org-exp-bibtex-docites (lambda ()
- (dolist (c (org-split-string (match-string 1) ","))
- (add-to-list 'cite-list c))))
-;; (message "cites: %s" cite-list)
- (let ((tmp (make-temp-file "org-exp-bibtex")))
- (with-temp-file tmp (dolist (i cite-list) (insert (concat i "\n"))))
- (setq tmp-files (cons tmp tmp-files))
- (setq extra-args (append extra-args `("-citefile" ,tmp)))))
-
- (when (not (eq 0 (apply 'call-process (append '("bibtex2html" nil nil nil)
- `("-a" "--nodoc" "--style" ,style "--no-header")
- extra-args
- (list (concat file ".bib"))))))
- (error "Executing bibtex2html failed"))
-
- (dolist (f tmp-files) (delete-file f)))
-
- (with-temp-buffer
- (save-match-data
- (insert-file-contents (concat file ".html"))
- (goto-char (point-min))
- (while (re-search-forward (org-re "a name=\"\\([-_[:word:]]+\\)\">\\([[:word:]]+\\)") nil t)
- (setq oebp-cite-plist (cons (cons (match-string 1) (match-string 2)) oebp-cite-plist)))
- (goto-char (point-min))
- (while (re-search-forward "<hr>" nil t)
- (replace-match "<hr/>" t t))
- (concat "\n#+BEGIN_HTML\n<div id=\"bibliography\">\n<h2>References</h2>\n" (buffer-string) "\n</div>\n#+END_HTML\n"))))
- ((eq org-export-current-backend 'latex) ;; Latex export
- (concat "\n#+LATEX: \\bibliographystyle{" style "}"
- "\n#+LATEX: \\bibliography{" file "}\n"))) t t)))
-
- ;; Convert cites to links in html
- (when (eq org-export-current-backend 'html)
- ;; Split citation commands with multiple keys
- (org-exp-bibtex-docites
- (lambda ()
- (let ((keys (save-match-data (org-split-string (match-string 1) ","))))
- (when (> (length keys) 1)
- (replace-match (mapconcat (lambda (k) (format "\\cite{%s}" k)) keys "")
- t t)))))
- ;; Replace the citation commands with links
- (org-exp-bibtex-docites
- (lambda () (let* ((cn (match-string 1))
- (cv (assoc cn oebp-cite-plist)))
-;; (message "L: %s" (concat "\[_{}[[" cn "][" (if cv (cdr cv) cn) "]]\]"))
- (replace-match (concat "\[_{}[[#" cn "][" (if cv (cdr cv) cn) "]]\]")) t t))))))
-
-(defun org-exp-bibtex-docites (fun)
- (save-excursion
- (save-match-data
- (goto-char (point-min))
- (when (eq org-export-current-backend 'html)
- (while (re-search-forward "\\\\cite{\\([^}\n]+\\)}" nil t)
- (apply fun nil))))))
-
-(defun org-exp-bibtex-options-to-plist (options)
- (save-match-data
- (flet ((f (o) (let ((s (split-string o ":"))) (cons (nth 0 s) (nth 1 s)))))
- (mapcar 'f (split-string options nil t)))))
-
-(add-hook 'org-export-preprocess-hook 'org-export-bibtex-preprocess)
-
-(provide 'org-exp-bibtex)
-
-;;; org-exp-bibtex.el ends here
diff --git a/contrib/lisp/org-expiry.el b/contrib/lisp/org-expiry.el
index 9f4517d..363bebe 100644
--- a/contrib/lisp/org-expiry.el
+++ b/contrib/lisp/org-expiry.el
@@ -1,8 +1,8 @@
;;; org-expiry.el --- expiry mechanism for Org entries
;;
-;; Copyright 2007-2012 Free Software Foundation, Inc.
+;; Copyright 2007-2013 Free Software Foundation, Inc.
;;
-;; Author: bzg AT gnu DOT org
+;; Author: Bastien Guerry
;; Version: 0.2
;; Keywords: org expiry
@@ -19,8 +19,7 @@
;; 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, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
@@ -83,7 +82,7 @@
:group 'org)
(defcustom org-expiry-inactive-timestamps nil
- "Insert inactive timestamps for the created and expired time properties"
+ "Insert inactive timestamps for created/expired properties."
:type 'boolean
:group 'org-expiry)
diff --git a/contrib/lisp/org-export-generic.el b/contrib/lisp/org-export-generic.el
deleted file mode 100644
index 4de38c7..0000000
--- a/contrib/lisp/org-export-generic.el
+++ /dev/null
@@ -1,1504 +0,0 @@
-;; org-export-generic.el --- Export frameworg with custom backends
-
-;; Copyright (C) 2009-2012 Free Software Foundation, Inc.
-
-;; Author: Wes Hardaker <hardaker at users dot sourceforge dot net>
-;; Keywords: outlines, hypermedia, calendar, wp, export
-;; Homepage: http://orgmode.org
-;; Version: 6.25trans
-;; Acks: Much of this code was stolen form the ascii export from Carsten
-;;
-;; This file is not yet part of GNU Emacs.
-;;
-;; GNU Emacs 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.
-
-;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-;;
-;; ----------------------------------------------------------------------
-;;
-;; OVERVIEW
-;;
-;; org-export-generic is basically a simple translation system that
-;; knows how to parse at least most of a .org buffer and then add
-;; various formatting prefixes before and after each section type. It
-;; does this by examining a property list stored in org-generic-alist.
-;; You can dynamically add propety lists of your own using the
-;; org-set-generic-type function:
-;;
-;; (org-set-generic-type
-;; "really-basic-text"
-;; '(:file-suffix ".txt"
-;; :key-binding ?R
-;;
-;; :title-format "=== %s ===\n"
-;; :body-header-section-numbers t
-;; :body-header-section-number-format "%s) "
-;; :body-section-header-prefix "\n"
-;; :body-section-header-suffix "\n"
-;; :body-line-format " %s\n"
-;; :body-line-wrap 75
-;; ))
-;;
-;; Note: Upper case key-bindings are reserved for your use. Lower
-;; case key bindings may conflict with future export-generic
-;; publications.
-;;
-;; Then run org-export (ctrl-c ctrl-e) and select generic or run
-;; org-export-generic. You'll then be prompted with a list of export
-;; types to choose from which will include your new type assigned to
-;; the key "r".
-;;
-;; ----------------------------------------------------------------------
-;;
-;; TODO (non-ordered)
-;; * handle function references
-;; * handle other types of multi-complex-listy-things to do
-;; ideas: (t ?- "%s" ?-)
-;; * handle indent specifiers better
-;; ideas: (4 ?\ "%s")
-;; * need flag to remove indents from body text
-;; * handle links
-;; * handle internationalization strings better
-;; * date/author/etc needs improvment (internationalization too)
-;; * allow specifying of section ordering
-;; ideas: :ordering ("header" "toc" "body" "footer")
-;; ^ matches current hard coded ordering
-;; * err, actually *do* a footer
-;; * deal with usage of org globals
-;; *** should we even consider them, or let the per-section specifiers do it
-;; *** answer: remove; mostly removed now
-;; * deal with interactive support for picking a export specifier label
-;; * char specifiers that need extra length because of formatting
-;; idea: (?- 4) for 4-longer
-;; * centering specifier
-;; idea: ('center " -- %s -- ")
-;; * remove more of the unneeded export-to-ascii copy code
-;; * tags
-;; *** supported now, but need separate format per tag
-;; *** allow different open/closing prefixes
-;; * properties
-;; * drawers
-;; * Escape camel-case for wiki exporters.
-;; * Adjust to depth limits on headers --- need to roll-over from headers
-;; to lists, as per other exporters
-;; * optmization (many plist extracts should be in let vars)
-;; * define defcustom spec for the specifier list
-;; * fonts: at least monospace is not handled at all here.
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; Commentary:
-
-(require 'org-exp)
-(require 'assoc)
-(eval-when-compile (require 'cl))
-
-(defgroup org-export-generic nil
- "Options specific for ASCII export of Org-mode files."
- :tag "Org Export ASCII"
- :group 'org-export)
-
-(defcustom org-export-generic-links-to-notes t
- "Non-nil means convert links to notes before the next headline.
-When nil, the link will be exported in place. If the line becomes long
-in this way, it will be wrapped."
- :group 'org-export-generic
- :type 'boolean)
-
-
-(defvar org-generic-current-indentation nil) ; For communication
-
-(defvar org-generic-alist
- '(
- ;;
- ;; generic DEMO exporter
- ;;
- ;; (this tries to use every specifier for demo purposes)
- ;;
- ("demo"
- :file-suffix ".txt"
- :key-binding ?d
-
- :header-prefix "<header>\n"
- :header-suffix "</header>\n"
-
- :author-export t
- :tags-export t
-
- :drawers-export t
-
-
- :title-prefix ?=
- :title-format "<h1>%s</h1>\n"
- :title-suffix ?=
-
- :date-export t
- :date-prefix "<date>"
- :date-format "<br /><b>Date:</b> <i>%s</i><br />"
- :date-suffix "</date>\n\n"
-
- :toc-export t
- :toc-header-prefix "<tocname>\n"
- :toc-header-format "__%s__\n"
- :toc-header-suffix "</tocname>\n"
-
- :toc-prefix "<toc>\n"
- :toc-suffix "</toc>\n"
-
- :toc-section-numbers t
- :toc-section-number-format "\#(%s) "
- :toc-format "--%s--"
- :toc-format-with-todo "!!%s!!\n"
- :toc-indent-char ?\
- :toc-indent-depth 4
-
- :toc-tags-export t
- :toc-tags-prefix " <tags>"
- :toc-tags-format "*%s*"
- :toc-tags-suffix "</tags>\n"
- :toc-tags-none-string "\n"
-
- :body-header-section-numbers 3 ; t = all, nil = none
-
- ; lists indicate different things per level
- ; list contents or straight value can either be a
- ; ?x char reference for printing strings that match the header len
- ; "" string to print directly
- :body-section-header-prefix ("<h1>" "<h2>" "<h3>"
- "<h4>" "<h5>" "<h6>")
- :body-section-header-format "%s"
- :body-section-header-suffix ("</h1>\n" "</h2>\n" "</h3>\n"
- "</h4>\n" "</h5>\n" "</h6>\n")
-
- :timestamps-export t
- :priorities-export t
- :todo-keywords-export t
-
- :body-tags-export t
- :body-tags-prefix " <tags>"
- :body-tags-suffix "</tags>\n"
-
- ; section prefixes/suffixes can be direct strings or lists as well
- :body-section-prefix "<secprefix>\n"
- :body-section-suffix "</secsuffix>\n"
- ; :body-section-prefix ("<sec1>\n" "<sec2>\n" "<sec3>\n")
- ; :body-section-suffix ("</sec1>\n" "</sec2>\n" "</sec3>\n")
-
-
- ; if preformated text should be included (eg, : prefixed)
- :body-line-export-preformated t
- :body-line-fixed-prefix "<pre>\n"
- :body-line-fixed-suffix "\n</pre>\n"
- :body-line-fixed-format "%s\n"
-
-
- :body-list-prefix "<list>\n"
- :body-list-suffix "</list>\n"
- :body-list-format "<li>%s</li>\n"
-
- :body-number-list-prefix "<ol>\n"
- :body-number-list-suffix "</ol>\n"
- :body-number-list-format "<li>%s</li>\n"
- :body-number-list-leave-number t
-
- :body-list-checkbox-todo "<checkbox type=\"todo\">"
- :body-list-checkbox-todo-end "</checkbox (todo)>"
- :body-list-checkbox-done "<checkbox type=\"done\">"
- :body-list-checkbox-done-end "</checkbox (done)>"
- :body-list-checkbox-half "<checkbox type=\"half\">"
- :body-list-checkbox-half-end "</checkbox (half)>"
-
-
-
-
- ; other body lines
- :body-line-format "%s"
- :body-line-wrap 60 ; wrap at 60 chars
-
- ; print above and below all body parts
- :body-text-prefix "<p>\n"
- :body-text-suffix "</p>\n"
-
- )
-
- ;;
- ;; ascii exporter
- ;;
- ;; (close to the original ascii specifier)
- ;;
- ("ascii"
- :file-suffix ".txt"
- :key-binding ?a
-
- :header-prefix ""
- :header-suffix ""
-
- :title-prefix ?=
- :title-format "%s\n"
- :title-suffix ?=
-
- :date-export t
- :date-prefix ""
- :date-format "Date: %s\n"
- :date-suffix ""
-
- :toc-header-prefix ""
- :toc-header-format "%s\n"
- :toc-header-suffix ?=
-
- :toc-export t
- :toc-section-numbers t
- :toc-section-number-format "%s "
- :toc-format "%s\n"
- :toc-format-with-todo "%s (*)\n"
- :toc-indent-char ?\
- :toc-indent-depth 4
-
- :body-header-section-numbers 3
- :body-section-prefix "\n"
-
- ; :body-section-header-prefix "\n"
- ; :body-section-header-format "%s\n"
- ; :body-section-header-suffix (?\$ ?\# ?^ ?\~ ?\= ?\-)
-
- :body-section-header-prefix ("" "" "" "* " " + " " - ")
- :body-section-header-format "%s\n"
- :body-section-header-suffix (?~ ?= ?- "\n" "\n" "\n")
-
- ; :body-section-marker-prefix ""
- ; :body-section-marker-chars (?\$ ?\# ?^ ?\~ ?\= ?\-)
- ; :body-section-marker-suffix "\n"
-
- :body-line-export-preformated t
- :body-line-format "%s\n"
- :body-line-wrap 75
-
- ; :body-text-prefix "<t>\n"
- ; :body-text-suffix "</t>\n"
-
-
- :body-bullet-list-prefix (?* ?+ ?-)
- ; :body-bullet-list-suffix (?* ?+ ?-)
- )
-
- ;;
- ;; wikipedia
- ;;
- ("wikipedia"
- :file-suffix ".txt"
- :key-binding ?w
-
- :header-prefix ""
- :header-suffix ""
-
- :title-format "= %s =\n"
-
- :date-export nil
-
- :toc-export nil
-
- :body-header-section-numbers nil
- :body-section-prefix "\n"
-
- :body-section-header-prefix ("= " "== " "=== "
- "==== " "===== " "====== ")
- :body-section-header-suffix (" =\n\n" " ==\n\n" " ===\n\n"
- " ====\n\n" " =====\n\n" " ======\n\n")
-
- :body-line-export-preformated t ;; yes/no/maybe???
- :body-line-format "%s\n"
- :body-line-wrap 75
-
- :body-line-fixed-format " %s\n"
-
- :body-list-format "* %s\n"
- :body-number-list-format "# %s\n"
-
- :body-bullet-list-prefix ("* " "** " "*** " "**** " "***** ")
- )
- ;;
- ;; mediawiki
- ;;
- ("mediawiki"
- :file-suffix ".txt"
- :key-binding ?m
-
- :header-prefix ""
- :header-suffix ""
-
- :title-format "= %s =\n"
-
- :date-export nil
-
- :toc-export nil
-
- :body-header-section-numbers nil
- :body-section-prefix "\n"
-
- :body-section-header-prefix ("= " "== " "=== "
- "==== " "===== " "====== ")
- :body-section-header-suffix (" =\n\n" " ==\n\n" " ===\n\n"
- " ====\n\n" " =====\n\n" " ======\n\n")
-
- :body-line-export-preformated t ;; yes/no/maybe???
- :body-line-format "%s\n"
- :body-line-wrap 75
-
- :body-line-fixed-format " %s\n"
-
- :body-list-format "* %s\n"
- :body-number-list-format "# %s\n"
-
- :body-bullet-list-prefix ("* " "** " "*** " "**** " "***** ")
- :body-list-checkbox-todo "&#9744; "
- :body-list-checkbox-done "&#9746; "
- :body-table-start "{|"
- :body-table-end "|}"
- :body-table-cell-start "|"
- :body-table-cell-end "\n"
- :body-table-last-cell-end "|-"
- :body-table-hline-start ""
-
-
- )
- ;;
- ;; internet-draft .xml for xml2rfc exporter
- ;;
- ("ietfid"
- ;; this tries to use every specifier for demo purposes
- :file-suffix ".xml"
- :key-binding ?i
-
- :title-prefix "<?xml version=\"1.0\"\?>
-<!DOCTYPE rfc SYSTEM \"rfc2629.dtd\" [
-<!ENTITY rfcs PUBLIC '' 'blah'>
-<?rfc strict=\"yes\" ?>
-<?rfc toc=\"yes\" ?>
-<?rfc tocdepth=\"4\" ?>
-<?rfc symrefs=\"yes\" ?>
-<?rfc compact=\"yes\" ?>
-<?rfc subcompact=\"no\" ?>
-<rfc category=\"std\" ipr=\"pre5378Trust200902\" docName=\"FILLME.txt\">
- <front>
-"
- :title-format "<title abbrev=\"ABBREV HERE\">\n%s\n</title>\n"
- :title-suffix "<author initials=\"A.A\" surname=\"LASTNAME\" fullname=\"FULL NAME\">
- <organization>Comany, Inc..</organization>
- <address>
- <postal>
- <street></street>
- <city></city>
- <region></region>
- <code></code>
- <country></country>
- </postal>
- <phone></phone>
- <email></email>
- </address>
- </author>
- <date month=\"FILLMONTH\" year=\"FILLYEAR\"/>
- <area>Operations and Management</area>
- <workgroup>FIXME</workgroup>
-<abstract>\n"
- :date-export nil
-
- :toc-export nil
-
- :body-header-section-numbers nil
-
- :body-section-header-format "<section title=\"%s\">\n"
- :body-section-suffix "</section>\n"
-
- ; if preformated text should be included (eg, : prefixed)
- :body-line-export-preformated t
- :body-line-fixed-prefix "<figure>\n<artwork>\n"
- :body-line-fixed-suffix "\n</artwork>\n</figure>\n"
-
- ; other body lines
- :body-line-format "%s"
- :body-line-wrap 75
-
- ; print above and below all body parts
- :body-text-prefix "<t>\n"
- :body-text-suffix "</t>\n"
-
- :body-list-prefix "<list style=\"symbols\">\n"
- :body-list-suffix "</list>\n"
- :body-list-format "<t>%s</t>\n"
-
- )
- ("trac-wiki"
- :file-suffix ".txt"
- :key-binding ?T
-
- ;; lifted from wikipedia exporter
- :header-prefix ""
- :header-suffix ""
-
- :title-format "= %s =\n"
-
- :date-export nil
-
- :toc-export nil
-
- :body-header-section-numbers nil
- :body-section-prefix "\n"
-
- :body-section-header-prefix (" == " " === " " ==== "
- " ===== " )
- :body-section-header-suffix (" ==\n\n" " ===\n\n" " ====\n\n"
- " =====\n\n" " ======\n\n" " =======\n\n")
-
- :body-line-export-preformated t ;; yes/no/maybe???
- :body-line-format "%s\n"
- :body-line-wrap 75
-
- :body-line-fixed-format " %s\n"
-
- :body-list-format " * %s\n"
- :body-number-list-format " # %s\n"
- ;; :body-list-prefix "LISTSTART"
- ;; :body-list-suffix "LISTEND"
-
- ;; this is ignored! [2010/02/02:rpg]
- :body-bullet-list-prefix ("* " "** " "*** " "**** " "***** ")
- )
- ("tikiwiki"
- :file-suffix ".txt"
- :key-binding ?U
-
- ;; lifted from wikipedia exporter
- :header-prefix ""
- :header-suffix ""
-
- :title-format "-= %s =-\n"
-
- :date-export nil
-
- :toc-export nil
-
- :body-header-section-numbers nil
- :body-section-prefix "\n"
-
- :body-section-header-prefix ("! " "!! " "!!! " "!!!! "
- "!!!!! " "!!!!!! " "!!!!!!! ")
- :body-section-header-suffix (" \n" " \n" " \n"
- " \n" " \n" " \n")
-
-
- :body-line-export-preformated t ;; yes/no/maybe???
- :body-line-format "%s "
- :body-line-wrap nil
-
- :body-line-fixed-format " %s\n"
-
- :body-list-format "* %s\n"
- :body-number-list-format "# %s\n"
- ;; :body-list-prefix "LISTSTART"
- ;; :body-list-suffix "LISTEND"
- :blockquote-start "\n^\n"
- :blockquote-end "^\n\n"
- :body-newline-paragraph "\n"
- :bold-format "__%s__"
- :italic-format "''%s''"
- :underline-format "===%s==="
- :strikethrough-format "--%s--"
- :code-format "-+%s+-"
- :verbatim-format "~pp~%s~/pp~"
- )
- )
- "A assoc list of property lists to specify export definitions"
-)
-
-(setq org-generic-export-type "demo")
-
-(defvar org-export-generic-section-type "")
-(defvar org-export-generic-section-suffix "")
-
-;;;###autoload
-(defun org-set-generic-type (type definition)
- "Adds a TYPE and DEFINITION to the existing list of defined generic
-export definitions."
- (aput 'org-generic-alist type definition))
-
-;;; helper functions for org-set-generic-type
-(defvar org-export-generic-keywords nil)
-(defmacro* def-org-export-generic-keyword (keyword
- &key documentation
- type)
- "Define KEYWORD as a legitimate element for inclusion in
-the body of an org-set-generic-type definition."
- `(progn
- (pushnew ,keyword org-export-generic-keywords)
- ;; TODO: push the documentation and type information
- ;; somewhere where it will do us some good.
- ))
-
-(def-org-export-generic-keyword :body-newline-paragraph
- :documentation "Bound either to NIL or to a pattern to be
-inserted in the output for every blank line in the input.
- The intention is to handle formats where text is flowed, and
-newlines are interpreted as significant \(e.g., as indicating
-preformatted text\). A common non-nil value for this keyword
-is \"\\n\". Should typically be combined with a value for
-:body-line-format that does NOT end with a newline."
- :type string)
-
-;;; fontification keywords
-(def-org-export-generic-keyword :bold-format)
-(def-org-export-generic-keyword :italic-format)
-(def-org-export-generic-keyword :underline-format)
-(def-org-export-generic-keyword :strikethrough-format)
-(def-org-export-generic-keyword :code-format)
-(def-org-export-generic-keyword :verbatim-format)
-
-
-
-
-(defun org-export-generic-remember-section (type suffix &optional prefix)
- (setq org-export-generic-section-type type)
- (setq org-export-generic-section-suffix suffix)
- (if prefix
- (insert prefix))
-)
-
-(defun org-export-generic-check-section (type &optional prefix suffix)
- "checks to see if type is already in use, or we're switching parts
-If we're switching, then insert a potentially previously remembered
-suffix, and insert the current prefix immediately and then save the
-suffix a later change time."
-
- (when (not (equal type org-export-generic-section-type))
- (if org-export-generic-section-suffix
- (insert org-export-generic-section-suffix))
- (setq org-export-generic-section-type type)
- (setq org-export-generic-section-suffix suffix)
- (if prefix
- (insert prefix))))
-
-;;;###autoload
-(defun org-export-generic (arg)
- "Export the outline as generic output.
-If there is an active region, export only the region.
-The prefix ARG specifies how many levels of the outline should become
-underlined headlines. The default is 3."
- (interactive "P")
- (setq-default org-todo-line-regexp org-todo-line-regexp)
- (let* ((opt-plist (org-combine-plists (org-default-export-plist)
- (org-infile-export-plist)))
- (region-p (org-region-active-p))
- (rbeg (and region-p (region-beginning)))
- (rend (and region-p (region-end)))
- (subtree-p
- (when region-p
- (save-excursion
- (goto-char rbeg)
- (and (org-at-heading-p)
- (>= (org-end-of-subtree t t) rend)))))
- (level-offset (if subtree-p
- (save-excursion
- (goto-char rbeg)
- (+ (funcall outline-level)
- (if org-odd-levels-only 1 0)))
- 0))
- (opt-plist (setq org-export-opt-plist
- (if subtree-p
- (org-export-add-subtree-options opt-plist rbeg)
- opt-plist)))
-
- helpstart
- (bogus (mapc (lambda (x)
- (setq helpstart
- (concat helpstart "\["
- (char-to-string
- (plist-get (cdr x) :key-binding))
- "] " (car x) "\n")))
- org-generic-alist))
-
- (help (concat helpstart "
-
-\[ ] the current setting of the org-generic-export-type variable
-"))
-
- (cmds
-
- (append
- (mapcar (lambda (x)
- (list
- (plist-get (cdr x) :key-binding)
- (car x)))
- org-generic-alist)
- (list (list ? "default"))))
-
- r1 r2 ass
-
- ;; read in the type to use
- (export-plist
- (progn
- (save-excursion
- (save-window-excursion
- (delete-other-windows)
- (with-output-to-temp-buffer "*Org Export/Generic Styles Help*"
- (princ help))
- (org-fit-window-to-buffer (get-buffer-window
- "*Org Export/Generic Styles Help*"))
- (message "Select command: ")
- (setq r1 (read-char-exclusive))))
- (setq r2 (if (< r1 27) (+ r1 96) r1))
- (unless (setq ass (cadr (assq r2 cmds)))
- (error "No command associated with key %c" r1))
-
- (cdr (assoc
- (if (equal ass "default") org-generic-export-type ass)
- org-generic-alist))))
-
- (custom-times org-display-custom-times)
- (org-generic-current-indentation '(0 . 0))
- (level 0) (old-level 0) line txt lastwastext
- (umax nil)
- (umax-toc nil)
- (case-fold-search nil)
- (bfname (buffer-file-name (or (buffer-base-buffer) (current-buffer))))
- (filesuffix (or (plist-get export-plist :file-suffix) ".foo"))
- (filename (concat (file-name-as-directory
- (org-export-directory :ascii opt-plist))
- (file-name-sans-extension
- (or (and subtree-p
- (org-entry-get (region-beginning)
- "EXPORT_FILE_NAME" t))
- (file-name-nondirectory bfname)))
- filesuffix))
- (filename (if (equal (file-truename filename)
- (file-truename bfname))
- (concat filename filesuffix)
- filename))
- (buffer (find-file-noselect filename))
- (org-levels-open (make-vector org-level-max nil))
- (odd org-odd-levels-only)
- (date (plist-get opt-plist :date))
- (author (plist-get opt-plist :author))
- (title (or (and subtree-p (org-export-get-title-from-subtree))
- (plist-get opt-plist :title)
- (and (not
- (plist-get opt-plist :skip-before-1st-heading))
- (org-export-grab-title-from-buffer))
- (file-name-sans-extension
- (file-name-nondirectory bfname))))
- (email (plist-get opt-plist :email))
- (language (plist-get opt-plist :language))
- (quote-re0 (concat "^[ \t]*" org-quote-string "\\>"))
-; (quote-re (concat "^\\(\\*+\\)\\([ \t]*" org-quote-string "\\>\\)"))
- (todo nil)
- (lang-words nil)
- (region
- (buffer-substring
- (if (org-region-active-p) (region-beginning) (point-min))
- (if (org-region-active-p) (region-end) (point-max))))
- (org-export-current-backend 'org-export-generic)
- (lines (org-split-string
- (org-export-preprocess-string
- region
- :for-backend 'ascii
- :skip-before-1st-heading
- (plist-get opt-plist :skip-before-1st-heading)
- :drawers (plist-get export-plist :drawers-export)
- :tags (plist-get export-plist :tags-export)
- :priority (plist-get export-plist :priority-export)
- :footnotes (plist-get export-plist :footnotes-export)
- :timestamps (plist-get export-plist :timestamps-export)
- :todo-keywords (plist-get export-plist :todo-keywords-export)
- :verbatim-multiline t
- :select-tags (plist-get export-plist :select-tags-export)
- :exclude-tags (plist-get export-plist :exclude-tags-export)
- :emph-multiline t
- :archived-trees
- (plist-get export-plist :archived-trees-export)
- :add-text (plist-get opt-plist :text))
- "\n"))
- ;; export-generic plist variables
- (withtags (plist-get export-plist :tags-export))
- (tagsintoc (plist-get export-plist :toc-tags-export))
- (tocnotagsstr (or (plist-get export-plist :toc-tags-none-string) ""))
- (tocdepth (plist-get export-plist :toc-indent-depth))
- (tocindentchar (plist-get export-plist :toc-indent-char))
- (tocsecnums (plist-get export-plist :toc-section-numbers))
- (tocsecnumform (plist-get export-plist :toc-section-number-format))
- (tocformat (plist-get export-plist :toc-format))
- (tocformtodo (plist-get export-plist :toc-format-with-todo))
- (tocprefix (plist-get export-plist :toc-prefix))
- (tocsuffix (plist-get export-plist :toc-suffix))
- (bodyfixedpre (plist-get export-plist :body-line-fixed-prefix))
- (bodyfixedsuf (plist-get export-plist :body-line-fixed-suffix))
- (bodyfixedform (or (plist-get export-plist :body-line-fixed-format)
- "%s"))
- (listprefix (plist-get export-plist :body-list-prefix))
- (listsuffix (plist-get export-plist :body-list-suffix))
- (listformat (or (plist-get export-plist :body-list-format) "%s\n"))
- (numlistleavenum
- (plist-get export-plist :body-number-list-leave-number))
- (numlistprefix (plist-get export-plist :body-number-list-prefix))
- (numlistsuffix (plist-get export-plist :body-number-list-suffix))
- (numlistformat
- (or (plist-get export-plist :body-number-list-format) "%s\n"))
- (listchecktodo
- (or (plist-get export-plist :body-list-checkbox-todo) "\\1"))
- (listcheckdone
- (or (plist-get export-plist :body-list-checkbox-done) "\\1"))
- (listcheckhalf
- (or (plist-get export-plist :body-list-checkbox-half) "\\1"))
- (listchecktodoend
- (or (plist-get export-plist :body-list-checkbox-todo-end) ""))
- (listcheckdoneend
- (or (plist-get export-plist :body-list-checkbox-done-end) ""))
- (listcheckhalfend
- (or (plist-get export-plist :body-list-checkbox-half-end) ""))
- (bodytablestart
- (or (plist-get export-plist :body-table-start) ""))
- (bodytableend
- (or (plist-get export-plist :body-table-end) ""))
- (bodytablerowstart
- (or (plist-get export-plist :body-table-row-start) ""))
- (bodytablerowend
- (or (plist-get export-plist :body-table-row-end) ""))
- (bodytablecellstart
- (or (plist-get export-plist :body-table-cell-start) ""))
- (bodytablecellend
- (or (plist-get export-plist :body-table-cell-end) ""))
- (bodytablefirstcellstart
- (or (plist-get export-plist :body-table-first-cell-start) ""))
- (bodytableinteriorcellstart
- (or (plist-get export-plist :body-table-interior-cell-start) ""))
- (bodytableinteriorcellend
- (or (plist-get export-plist :body-table-interior-cell-end) ""))
- (bodytablelastcellend
- (or (plist-get export-plist :body-table-last-cell-end) ""))
- (bodytablehlinestart
- (or (plist-get export-plist :body-table-hline-start) " \\1"))
- (bodytablehlineend
- (or (plist-get export-plist :body-table-hline-end) ""))
-
-
-
- (bodynewline-paragraph (plist-get export-plist :body-newline-paragraph))
- (bodytextpre (plist-get export-plist :body-text-prefix))
- (bodytextsuf (plist-get export-plist :body-text-suffix))
- (bodylinewrap (plist-get export-plist :body-line-wrap))
- (bodylineform (or (plist-get export-plist :body-line-format) "%s"))
- (blockquotestart (or (plist-get export-plist :blockquote-start) "\n\n\t"))
- (blockquoteend (or (plist-get export-plist :blockquote-end) "\n\n"))
-
- ;; dynamic variables used heinously in fontification
- ;; not referenced locally...
- (format-boldify (plist-get export-plist :bold-format))
- (format-italicize (plist-get export-plist :italic-format))
- (format-underline (plist-get export-plist :underline-format))
- (format-strikethrough (plist-get export-plist :strikethrough-format))
- (format-code (plist-get export-plist :code-format))
- (format-verbatim (plist-get export-plist :verbatim-format))
-
-
-
- thetoc toctags have-headings first-heading-pos
- table-open table-buffer link-buffer link desc desc0 rpl wrap)
-
- (let ((inhibit-read-only t))
- (org-unmodified
- (remove-text-properties (point-min) (point-max)
- '(:org-license-to-kill t))))
-
- (setq org-min-level (org-get-min-level lines level-offset))
- (setq org-last-level org-min-level)
- (org-init-section-numbers)
-
- (find-file-noselect filename)
-
- (setq lang-words (or (assoc language org-export-language-setup)
- (assoc "en" org-export-language-setup)))
- (switch-to-buffer-other-window buffer)
- (erase-buffer)
- (fundamental-mode)
- ;; create local variables for all options, to make sure all called
- ;; functions get the correct information
- (mapc (lambda (x)
- (set (make-local-variable (nth 2 x))
- (plist-get opt-plist (car x))))
- org-export-plist-vars)
- (org-set-local 'org-odd-levels-only odd)
- (setq umax (if arg (prefix-numeric-value arg)
- org-export-headline-levels))
- (setq umax-toc umax)
-
- ;; File header
- (if title
- (insert
- (org-export-generic-header title export-plist
- :title-prefix
- :title-format
- :title-suffix)))
-
- (if (and (or author email)
- (plist-get export-plist :author-export))
- (insert (concat (nth 1 lang-words) ": " (or author "")
- (if email (concat " <" email ">") "")
- "\n")))
-
- (cond
- ((and date (string-match "%" date))
- (setq date (format-time-string date)))
- (date)
- (t (setq date (format-time-string "%Y-%m-%d %T %Z"))))
-
- (if (and date (plist-get export-plist :date-export))
- (insert
- (org-export-generic-header date export-plist
- :date-prefix
- :date-format
- :date-suffix)))
-
- ;; export the table of contents first
- (if (plist-get export-plist :toc-export)
- (progn
- (push
- (org-export-generic-header (nth 3 lang-words) export-plist
- :toc-header-prefix
- :toc-header-format
- :toc-header-suffix)
- thetoc)
-
- (if tocprefix
- (push tocprefix thetoc))
-
- (mapc '(lambda (line)
- (if (string-match org-todo-line-regexp line)
- ;; This is a headline
- (progn
- (setq have-headings t)
- (setq level (- (match-end 1) (match-beginning 1)
- level-offset)
- level (org-tr-level level)
- txt (match-string 3 line)
- todo
- (or (and org-export-mark-todo-in-toc
- (match-beginning 2)
- (not (member (match-string 2 line)
- org-done-keywords)))
- ; TODO, not DONE
- (and org-export-mark-todo-in-toc
- (= level umax-toc)
- (org-search-todo-below
- line lines level))))
- (setq txt (org-html-expand-for-generic txt))
-
- (while (string-match org-bracket-link-regexp txt)
- (setq txt
- (replace-match
- (match-string (if (match-end 2) 3 1) txt)
- t t txt)))
-
- (if (and (not tagsintoc)
- (string-match
- (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$")
- txt))
- (setq txt (replace-match "" t t txt))
- ; include tags but formated
- (if (string-match
- (org-re "[ \t]+:\\([[:alnum:]_@:]+\\):[ \t]*$")
- txt)
- (progn
- (setq
- toctags
- (org-export-generic-header
- (match-string 1 txt)
- export-plist :toc-tags-prefix
- :toc-tags-format :toc-tags-suffix))
- (string-match
- (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$")
- txt)
- (setq txt (replace-match "" t t txt)))
- (setq toctags tocnotagsstr)))
-
- (if (string-match quote-re0 txt)
- (setq txt (replace-match "" t t txt)))
-
- (if (<= level umax-toc)
- (progn
- (push
- (concat
-
- (make-string
- (* (max 0 (- level org-min-level)) tocdepth)
- tocindentchar)
-
- (if tocsecnums
- (format tocsecnumform
- (org-section-number level))
- "")
-
- (format
- (if todo tocformtodo tocformat)
- txt)
-
- toctags)
-
- thetoc)
- (setq org-last-level level))
- ))))
- lines)
- (if tocsuffix
- (push tocsuffix thetoc))
- (setq thetoc (if have-headings (nreverse thetoc) nil))))
-
- (org-init-section-numbers)
- (org-export-generic-check-section "top")
- (while (setq line (pop lines))
- (when (and link-buffer (string-match org-outline-regexp-bol line))
- (org-export-generic-push-links (nreverse link-buffer))
- (setq link-buffer nil))
- (setq wrap nil)
- ;; Remove the quoted HTML tags.
- ;; XXX
- (setq line (org-html-expand-for-generic line))
- ;; Replace links with the description when possible
- ;; XXX
- (while (string-match org-bracket-link-regexp line)
- (setq link (match-string 1 line)
- desc0 (match-string 3 line)
- desc (or desc0 (match-string 1 line)))
- (if (and (> (length link) 8)
- (equal (substring link 0 8) "coderef:"))
- (setq line (replace-match
- (format (org-export-get-coderef-format (substring link 8) desc)
- (cdr (assoc
- (substring link 8)
- org-export-code-refs)))
- t t line))
- (setq rpl (concat "["
- (or (match-string 3 line) (match-string 1 line))
- "]"))
- (when (and desc0 (not (equal desc0 link)))
- (if org-export-generic-links-to-notes
- (push (cons desc0 link) link-buffer)
- (setq rpl (concat rpl " (" link ")")
- wrap (+ (length line) (- (length (match-string 0 line)))
- (length desc)))))
- (setq line (replace-match rpl t t line))))
- (when custom-times
- (setq line (org-translate-time line)))
- (cond
- ((string-match "^\\(\\*+\\)[ \t]+\\(.*\\)" line)
- ;;
- ;; a Headline
- ;;
- (org-export-generic-check-section "headline")
-
- (setq first-heading-pos (or first-heading-pos (point)))
- (setq level (org-tr-level (- (match-end 1) (match-beginning 1)
- level-offset))
- txt (match-string 2 line))
- (org-generic-level-start level old-level txt umax export-plist lines)
- (setq old-level level))
-
- ((and org-export-with-tables
- (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)" line))
- ;;
- ;; a Table
- ;;
- (org-export-generic-check-section "table")
-
- (if (not table-open)
- ;; New table starts
- (setq table-open t table-buffer nil))
- ;; Accumulate table lines
- (setq table-buffer (cons line table-buffer))
- (when (or (not lines)
- (not (string-match "^\\([ \t]*\\)\\(|\\|\\+-+\\+\\)"
- (car lines))))
- (setq table-open nil
- table-buffer (nreverse table-buffer))
- (insert (mapconcat
- (lambda (x)
- (org-fix-indentation x org-generic-current-indentation))
- (org-format-table-generic table-buffer)
- "\n") "\n")))
-
- ((string-match "^\\([ \t]*\\)\\(:\\( \\|$\\)\\)" line)
- ;;
- ;; pre-formatted text
- ;;
- (setq line (replace-match "\\1" nil nil line))
-
- (org-export-generic-check-section "preformat" bodyfixedpre bodyfixedsuf)
-
- (insert (format bodyfixedform line)))
-
- ((or (string-match "^\\([ \t]*\\)\\([\-\+][ \t]*\\)" line)
- ;; if the bullet list item is an asterisk, the leading space is /mandatory/
- ;; [2010/02/02:rpg]
- (string-match "^\\([ \t]+\\)\\(\\*[ \t]*\\)" line))
- ;;
- ;; plain list item
- ;; TODO: nested lists
- ;;
- ;; first add a line break between any previous paragraph or line item and this
- ;; one
- (when bodynewline-paragraph
- (insert bodynewline-paragraph))
-
- ;; I believe this gets rid of leading whitespace.
- (setq line (replace-match "" nil nil line))
-
- ;; won't this insert the suffix /before/ the last line of the list?
- ;; also isn't it spoofed by bulleted lists that have a line skip between the list items
- ;; unless 'org-empty-line-terminates-plain-lists' is true?
- (org-export-generic-check-section "liststart" listprefix listsuffix)
-
- ;; deal with checkboxes
- (cond
- ((string-match "^\\(\\[ \\]\\)[ \t]*" line)
- (setq line (concat (replace-match listchecktodo nil nil line)
- listchecktodoend)))
- ((string-match "^\\(\\[X\\]\\)[ \t]*" line)
- (setq line (concat (replace-match listcheckdone nil nil line)
- listcheckdoneend)))
- ((string-match "^\\(\\[/\\]\\)[ \t]*" line)
- (setq line (concat (replace-match listcheckhalf nil nil line)
- listcheckhalfend)))
- )
-
- (insert (format listformat (org-export-generic-fontify line))))
- ((string-match "^\\([ \t]+\\)\\([0-9]+\\.[ \t]*\\)" line)
- ;;
- ;; numbered list item
- ;;
- ;; TODO: nested lists
- ;;
- (setq line (replace-match (if numlistleavenum "\\2" "") nil nil line))
-
- (org-export-generic-check-section "numliststart"
- numlistprefix numlistsuffix)
-
- ;; deal with checkboxes
- ;; TODO: whoops; leaving the numbers is a problem for ^ matching
- (cond
- ((string-match "\\(\\[ \\]\\)[ \t]*" line)
- (setq line (concat (replace-match listchecktodo nil nil line)
- listchecktodoend)))
- ((string-match "\\(\\[X\\]\\)[ \t]*" line)
- (setq line (concat (replace-match listcheckdone nil nil line)
- listcheckdoneend)))
- ((string-match "\\(\\[/\\]\\)[ \t]*" line)
- (setq line (concat (replace-match listcheckhalf nil nil line)
- listcheckhalfend)))
- )
-
- (insert (format numlistformat (org-export-generic-fontify line))))
-
- ((equal line "ORG-BLOCKQUOTE-START")
- (setq line blockquotestart))
- ((equal line "ORG-BLOCKQUOTE-END")
- (setq line blockquoteend))
- ((string-match "^\\s-*$" line)
- ;; blank line
- (if bodynewline-paragraph
- (insert bodynewline-paragraph)))
- (t
- ;;
- ;; body
- ;;
- (org-export-generic-check-section "body" bodytextpre bodytextsuf)
-
- (setq line
- (org-export-generic-fontify line))
-
- ;; XXX: properties? list?
- (if (string-match "^\\([ \t]*\\)\\([-+*][ \t]+\\)\\(.*?\\)\\( ::\\)" line)
- (setq line (replace-match "\\1\\3:" t nil line)))
-
- (setq line (org-fix-indentation line org-generic-current-indentation))
-
- ;; Remove forced line breaks
- (if (string-match "\\\\\\\\[ \t]*$" line)
- (setq line (replace-match "" t t line)))
-
- (if bodylinewrap
- ;; XXX: was dependent on wrap var which was calculated by???
- (if (> (length line) bodylinewrap)
- (setq line
- (org-export-generic-wrap line bodylinewrap))
- (setq line line)))
- (insert (format bodylineform line)))))
-
- ;; if we're at a level > 0; insert the closing body level stuff
- (let ((counter 0))
- (while (> (- level counter) 0)
- (insert
- (org-export-generic-format export-plist :body-section-suffix 0
- (- level counter)))
- (setq counter (1+ counter))))
-
- (org-export-generic-check-section "bottom")
-
- (org-export-generic-push-links (nreverse link-buffer))
-
- (normal-mode)
-
- ;; insert the table of contents
- (when thetoc
- (goto-char (point-min))
- (if (re-search-forward "^[ \t]*\\[TABLE-OF-CONTENTS\\][ \t]*$" nil t)
- (progn
- (goto-char (match-beginning 0))
- (replace-match ""))
- (goto-char first-heading-pos))
- (mapc 'insert thetoc)
- (or (looking-at "[ \t]*\n[ \t]*\n")
- (insert "\n\n")))
-
- ;; Convert whitespace place holders
- (goto-char (point-min))
- (let (beg end)
- (while (setq beg (next-single-property-change (point) 'org-whitespace))
- (setq end (next-single-property-change beg 'org-whitespace))
- (goto-char beg)
- (delete-region beg end)
- (insert (make-string (- end beg) ?\ ))))
-
- (save-buffer)
-
- ;; remove display and invisible chars
- (let (beg end)
- (goto-char (point-min))
- (while (setq beg (next-single-property-change (point) 'display))
- (setq end (next-single-property-change beg 'display))
- (delete-region beg end)
- (goto-char beg)
- (insert "=>"))
- (goto-char (point-min))
- (while (setq beg (next-single-property-change (point) 'org-cwidth))
- (setq end (next-single-property-change beg 'org-cwidth))
- (delete-region beg end)
- (goto-char beg)))
- (goto-char (point-min))))
-
-
-(defun org-export-generic-format (export-plist prop &optional len n reverse)
- "converts a property specification to a string given types of properties
-
-The EXPORT-PLIST should be defined as the lookup plist.
-The PROP should be the property name to search for in it.
-LEN is set to the length of multi-characters strings to generate (or 0)
-N is the tree depth
-REVERSE means to reverse the list if the plist match is a list
- "
- (let* ((prefixtype (plist-get export-plist prop))
- subtype)
- (cond
- ((null prefixtype) "")
- ((and len (char-or-string-p prefixtype) (not (stringp prefixtype)))
- ;; sequence of chars
- (concat (make-string len prefixtype) "\n"))
- ((stringp prefixtype)
- prefixtype)
- ((and n (listp prefixtype))
- (if reverse
- (setq prefixtype (reverse prefixtype)))
- (setq subtype (if (> n (length prefixtype))
- (car (last prefixtype))
- (nth (1- n) prefixtype)))
- (if (stringp subtype)
- subtype
- (concat (make-string len subtype) "\n")))
- (t ""))
- ))
-
-(defun org-export-generic-header (header export-plist
- prefixprop formatprop postfixprop
- &optional n reverse)
- "convert a header to an output string given formatting property names"
- (let* ((formatspec (plist-get export-plist formatprop))
- (len (length header)))
- (concat
- (org-export-generic-format export-plist prefixprop len n reverse)
- (format (or formatspec "%s") header)
- (org-export-generic-format export-plist postfixprop len n reverse))
- ))
-
-(defun org-export-generic-preprocess (parameters)
- "Do extra work for ASCII export"
- ;; Put quotes around verbatim text
- (goto-char (point-min))
- (while (re-search-forward org-verbatim-re nil t)
- (goto-char (match-end 2))
- (backward-delete-char 1) (insert "'")
- (goto-char (match-beginning 2))
- (delete-char 1) (insert "`")
- (goto-char (match-end 2)))
- ;; Remove target markers
- (goto-char (point-min))
- (while (re-search-forward "<<<?\\([^<>]*\\)>>>?\\([ \t]*\\)" nil t)
- (replace-match "\\1\\2")))
-
-(defun org-html-expand-for-generic (line)
- "Handle quoted HTML for ASCII export."
- (if org-export-html-expand
- (while (string-match "@<[^<>\n]*>" line)
- ;; We just remove the tags for now.
- (setq line (replace-match "" nil nil line))))
- line)
-
-(defun org-export-generic-wrap (line where)
- "Wrap LINE at or before WHERE."
- (let* ((ind (org-get-indentation line))
- (indstr (make-string ind ?\ ))
- (len (length line))
- (result "")
- pos didfirst)
- (while (> len where)
- (catch 'found
- (loop for i from where downto (/ where 2) do
- (and (equal (aref line i) ?\ )
- (setq pos i)
- (throw 'found t))))
- (if pos
- (progn
- (setq result
- (concat result
- (if didfirst indstr "")
- (substring line 0 pos)
- "\n"))
- (setq didfirst t)
- (setq line (substring line (1+ pos)))
- (setq len (length line)))
- (setq result (concat result line))
- (setq len 0)))
- (concat result indstr line)))
-
-(defun org-export-generic-push-links (link-buffer)
- "Push out links in the buffer."
- (when link-buffer
- ;; We still have links to push out.
- (insert "\n")
- (let ((ind ""))
- (save-match-data
- (if (save-excursion
- (re-search-backward
- "^\\(\\([ \t]*\\)\\|\\(\\*+ \\)\\)[^ \t\n]" nil t))
- (setq ind (or (match-string 2)
- (make-string (length (match-string 3)) ?\ )))))
- (mapc (lambda (x) (insert ind "[" (car x) "]: " (cdr x) "\n"))
- link-buffer))
- (insert "\n")))
-
-(defun org-generic-level-start (level old-level title umax export-plist
- &optional lines)
- "Insert a new level in a generic export."
- (let ((n (- level umax 1))
- (ind 0)
- (diff (- level old-level)) (counter 0)
- (secnums (plist-get export-plist :body-header-section-numbers))
- (secnumformat
- (plist-get export-plist :body-header-section-number-format))
- char tagstring)
- (unless org-export-with-tags
- (if (string-match (org-re "[ \t]+\\(:[[:alnum:]_@:]+:\\)[ \t]*$") title)
- (setq title (replace-match "" t t title))))
-
- (cond
- ;; going deeper
- ((> level old-level)
- (while (< (+ old-level counter) (1- level))
- (insert
- (org-export-generic-format export-plist :body-section-prefix 0
- (+ old-level counter)))
- (setq counter (1+ counter))
- ))
- ;; going up
- ((< level old-level)
- (while (> (- old-level counter) (1- level))
- (insert
- (org-export-generic-format export-plist :body-section-suffix 0
- (- old-level counter)))
- (setq counter (1+ counter))
- ))
- ;; same level
- ((= level old-level)
- (insert
- (org-export-generic-format export-plist :body-section-suffix 0 level))
- )
- )
- (insert
- (org-export-generic-format export-plist :body-section-prefix 0 level))
-
- (if (and org-export-with-section-numbers
- secnums
- (or (not (numberp secnums))
- (< level secnums)))
- (setq title
- (concat (format (or secnumformat "%s ")
- (org-section-number level)) title)))
-
- ;; handle tags and formatting
- (if (string-match
- (org-re "[ \t]+:\\([[:alnum:]_@:]+\\):[ \t]*$") title)
- (progn
- (if (plist-get export-plist :body-tags-export)
- (setq tagstring (org-export-generic-header (match-string 1 title)
- export-plist
- :body-tags-prefix
- :body-tags-format
- :body-tags-suffix)))
- (string-match (org-re "[ \t]+:[[:alnum:]_@:]+:[ \t]*$") title)
- (setq title (replace-match "" t t title)))
- (setq tagstring (plist-get export-plist :body-tags-none-string)))
-
- (insert
- (org-export-generic-header title export-plist
- :body-section-header-prefix
- :body-section-header-format
- :body-section-header-suffix
- level))
- (if tagstring
- (insert tagstring))
-
- (setq org-generic-current-indentation '(0 . 0))))
-
-(defun org-insert-centered (s &optional underline)
- "Insert the string S centered and underline it with character UNDERLINE."
- (let ((ind (max (/ (- fill-column (string-width s)) 2) 0)))
- (insert (make-string ind ?\ ) s "\n")
- (if underline
- (insert (make-string ind ?\ )
- (make-string (string-width s) underline)
- "\n"))))
-
-(defvar org-table-colgroup-info nil)
-(defun org-format-table-generic (lines)
- "Format a table for ascii export."
- (if (stringp lines)
- (setq lines (org-split-string lines "\n")))
- (if (not (string-match "^[ \t]*|" (car lines)))
- ;; Table made by table.el - test for spanning
- lines
-
- ;; A normal org table
- ;; Get rid of hlines at beginning and end
- (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines)))
- (setq lines (nreverse lines))
- (if (string-match "^[ \t]*|-" (car lines)) (setq lines (cdr lines)))
- (setq lines (nreverse lines))
- (when org-export-table-remove-special-lines
- ;; Check if the table has a marking column. If yes remove the
- ;; column and the special lines
- (setq lines (org-table-clean-before-export lines)))
- ;; Get rid of the vertical lines except for grouping
- (let ((vl (org-colgroup-info-to-vline-list org-table-colgroup-info))
- (rtn (list bodytablestart)) line vl1 start)
- (while (setq line (pop lines))
- (setq line (concat bodytablerowstart line))
- (if (string-match org-table-hline-regexp line)
- (and (string-match "|\\(.*\\)|" line)
- (setq line (replace-match (concat bodytablehlinestart bodytablehlineend) t nil line)))
- (setq start 0 vl1 vl)
- (if (string-match "|\\(.*\\)|" line)
- (setq line (replace-match (concat bodytablefirstcellstart bodytablecellstart " \\1 " bodytablecellend bodytablelastcellend) t nil line)))
- (while (string-match "|" line start)
- (setq start (+ (match-end 0) (length (concat bodytablecellend bodytableinteriorcellend bodytableinteriorcellstart bodytablecellstart))))
- (or (pop vl1) (setq line (replace-match (concat bodytablecellend bodytableinteriorcellend bodytableinteriorcellstart bodytablecellstart) t t line)))))
- (setq line (concat line bodytablerowend))
- (push line rtn))
- (setq rtn (cons bodytableend rtn))
- (nreverse rtn))))
-
-(defun org-colgroup-info-to-vline-list (info)
- (let (vl new last)
- (while info
- (setq last new new (pop info))
- (if (or (memq last '(:end :startend))
- (memq new '(:start :startend)))
- (push t vl)
- (push nil vl)))
- (setq vl (nreverse vl))
- (and vl (setcar vl nil))
- vl))
-
-
-;;; FIXME: this should probably turn into a defconstant later [2010/05/20:rpg]
-(defvar org-export-generic-emphasis-alist
- '(("*" format-boldify nil)
- ("/" format-italicize nil)
- ("_" format-underline nil)
- ("+" format-strikethrough nil)
- ("=" format-code t)
- ("~" format-verbatim t))
- "Alist of org format -> formatting variables for fontification.
-Each element of the list is a list of three elements.
-The first element is the character used as a marker for fontification.
-The second element is a variable name, set in org-export-generic. That
-variable will be dereferenced to obtain a formatting string to wrap
-fontified text with.
-The third element decides whether to protect converted text from other
-conversions.")
-
-;;; Cargo-culted from the latex translation. I couldn't figure out how
-;;; to keep the structure since the generic export operates on lines, rather
-;;; than on a buffer as in the latex export, meaning that none of the
-;;; search forward code could be kept. This led me to rewrite the
-;;; whole thing recursively. A huge lose for efficiency (potentially),
-;;; but I couldn't figure out how to make the looping work.
-;;; Worse, it's /doubly/ recursive, because this function calls
-;;; org-export-generic-emph-format, which can call it recursively...
-;;; [2010/05/20:rpg]
-(defun org-export-generic-fontify (string)
- "Convert fontification according to generic rules."
- (if (string-match org-emph-re string)
- ;; The match goes one char after the *string*, except at the end of a line
- (let ((emph (assoc (match-string 3 string)
- org-export-generic-emphasis-alist))
- (beg (match-beginning 0))
- (end (match-end 0)))
- (unless emph
- (message "`org-export-generic-emphasis-alist' has no entry for formatting triggered by \"%s\""
- (match-string 3 string)))
- ;; now we need to determine whether we have strikethrough or
- ;; a list, which is a bit nasty
- (if (and (equal (match-string 3 string) "+")
- (save-match-data
- (string-match "\\`-+\\'" (match-string 4 string))))
- ;; a list --- skip this match and recurse on the point after the
- ;; first emph char...
- (concat (substring string 0 (1+ (match-beginning 3)))
- (org-export-generic-fontify (substring string (match-beginning 3))))
- (concat (substring string 0 beg) ;; part before the match
- (match-string 1 string)
- (org-export-generic-emph-format (second emph)
- (match-string 4 string)
- (third emph))
- (or (match-string 5 string) "")
- (org-export-generic-fontify (substring string end)))))
- string))
-
-(defun org-export-generic-emph-format (format-varname string protect)
- "Return a string that results from applying the markup indicated by
-FORMAT-VARNAME to STRING."
- (let ((format (symbol-value format-varname)))
- (let ((string-to-emphasize
- (if protect
- string
- (org-export-generic-fontify string))))
- (if format
- (format format string-to-emphasize)
- string-to-emphasize))))
-
-(provide 'org-generic)
-(provide 'org-export-generic)
-
-;;; org-export-generic.el ends here
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 <n.goaziou at gmail dot com>
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; 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 &alpha; and \\AA to
-&Aring;.
-
-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
- -----+----------+--------
- \\- &shy; \\-
- -- &ndash; --
- --- &mdash; ---
- ... &hellip; \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:<b>@@\" 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 "\\<example\\>" value) 'example)
- ((string-match "\\<src\\(?: +\\(.*\\)\\)?" value)
- (match-string 1 value))))
- ;; Minimal level of included file defaults to the child
- ;; level of the current headline, if any, or one. It
- ;; only applies is the file is meant to be included as
- ;; an Org one.
- (minlevel
- (and (not env)
- (if (string-match ":minlevel +\\([0-9]+\\)" value)
- (prog1 (string-to-number (match-string 1 value))
- (setq value (replace-match "" nil nil value)))
- (let ((cur (org-current-level)))
- (if cur (1+ (org-reduced-level cur)) 1))))))
- ;; Remove keyword.
- (delete-region (point) (progn (forward-line) (point)))
- (cond
- ((not (file-readable-p file)) (error "Cannot include file %s" file))
- ;; Check if files has already been parsed. Look after
- ;; inclusion lines too, as different parts of the same file
- ;; can be included too.
- ((member (list file lines) included)
- (error "Recursive file inclusion: %s" file))
- (t
- (cond
- ((eq env 'example)
- (insert
- (let ((ind-str (make-string ind ? ))
- (contents
- ;; Protect sensitive contents with commas.
- (replace-regexp-in-string
- "\\(^\\)\\([*]\\|[ \t]*#\\+\\)" ","
- (org-export--prepare-file-contents file lines)
- nil nil 1)))
- (format "%s#+BEGIN_EXAMPLE\n%s%s#+END_EXAMPLE\n"
- ind-str contents ind-str))))
- ((stringp env)
- (insert
- (let ((ind-str (make-string ind ? ))
- (contents
- ;; Protect sensitive contents with commas.
- (replace-regexp-in-string
- (if (string= env "org") "\\(^\\)\\(.\\)"
- "\\(^\\)\\([*]\\|[ \t]*#\\+\\)") ","
- (org-export--prepare-file-contents file lines)
- nil nil 1)))
- (format "%s#+BEGIN_SRC %s\n%s%s#+END_SRC\n"
- ind-str env contents ind-str))))
- (t
- (insert
- (with-temp-buffer
- (org-mode)
- (insert
- (org-export--prepare-file-contents file lines ind minlevel))
- (org-export-expand-include-keyword
- (cons (list file lines) included)
- (file-name-directory file))
- (buffer-string))))))))))))
-
-(defun org-export--prepare-file-contents (file &optional lines ind minlevel)
- "Prepare the contents of FILE for inclusion and return them as a string.
-
-When optional argument LINES is a string specifying a range of
-lines, include only those lines.
-
-Optional argument IND, when non-nil, is an integer specifying the
-global indentation of returned contents. Since its purpose is to
-allow an included file to stay in the same environment it was
-created \(i.e. a list item), it doesn't apply past the first
-headline encountered.
-
-Optional argument MINLEVEL, when non-nil, is an integer
-specifying the level that any top-level headline in the included
-file should have."
- (with-temp-buffer
- (insert-file-contents file)
- (when lines
- (let* ((lines (split-string lines "-"))
- (lbeg (string-to-number (car lines)))
- (lend (string-to-number (cadr lines)))
- (beg (if (zerop lbeg) (point-min)
- (goto-char (point-min))
- (forward-line (1- lbeg))
- (point)))
- (end (if (zerop lend) (point-max)
- (goto-char (point-min))
- (forward-line (1- lend))
- (point))))
- (narrow-to-region beg end)))
- ;; Remove blank lines at beginning and end of contents. The logic
- ;; behind that removal is that blank lines around include keyword
- ;; override blank lines in included file.
- (goto-char (point-min))
- (org-skip-whitespace)
- (beginning-of-line)
- (delete-region (point-min) (point))
- (goto-char (point-max))
- (skip-chars-backward " \r\t\n")
- (forward-line)
- (delete-region (point) (point-max))
- ;; If IND is set, preserve indentation of include keyword until
- ;; the first headline encountered.
- (when ind
- (unless (eq major-mode 'org-mode) (org-mode))
- (goto-char (point-min))
- (let ((ind-str (make-string ind ? )))
- (while (not (or (eobp) (looking-at org-outline-regexp-bol)))
- ;; Do not move footnote definitions out of column 0.
- (unless (and (looking-at org-footnote-definition-re)
- (eq (org-element-type (org-element-at-point))
- 'footnote-definition))
- (insert ind-str))
- (forward-line))))
- ;; When MINLEVEL is specified, compute minimal level for headlines
- ;; in the file (CUR-MIN), and remove stars to each headline so
- ;; that headlines with minimal level have a level of MINLEVEL.
- (when minlevel
- (unless (eq major-mode 'org-mode) (org-mode))
- (let ((levels (org-map-entries
- (lambda () (org-reduced-level (org-current-level))))))
- (when levels
- (let ((offset (- minlevel (apply 'min levels))))
- (unless (zerop offset)
- (when org-odd-levels-only (setq offset (* offset 2)))
- ;; Only change stars, don't bother moving whole
- ;; sections.
- (org-map-entries
- (lambda () (if (< offset 0) (delete-char (abs offset))
- (insert (make-string offset ?*))))))))))
- (buffer-string)))
-
-
-;;; Tools For Back-Ends
-;;
-;; A whole set of tools is available to help build new exporters. Any
-;; function general enough to have its use across many back-ends
-;; should be added here.
-;;
-;; As of now, functions operating on footnotes, headlines, links,
-;; macros, references, src-blocks, tables and tables of contents are
-;; implemented.
-
-;;;; For Affiliated Keywords
-;;
-;; `org-export-read-attribute' reads a property from a given element
-;; as a plist. It can be used to normalize affiliated keywords'
-;; syntax.
-
-(defun org-export-read-attribute (attribute element &optional property)
- "Turn ATTRIBUTE property from ELEMENT into a plist.
-
-When optional argument PROPERTY is non-nil, return the value of
-that property within attributes.
-
-This function assumes attributes are defined as \":keyword
-value\" pairs. It is appropriate for `:attr_html' like
-properties."
- (let ((attributes
- (let ((value (org-element-property attribute element)))
- (and value
- (read (format "(%s)" (mapconcat 'identity value " ")))))))
- (if property (plist-get attributes property) attributes)))
-
-
-;;;; For Export Snippets
-;;
-;; Every export snippet is transmitted to the back-end. Though, the
-;; latter will only retain one type of export-snippet, ignoring
-;; others, based on the former's target back-end. The function
-;; `org-export-snippet-backend' returns that back-end for a given
-;; export-snippet.
-
-(defun org-export-snippet-backend (export-snippet)
- "Return EXPORT-SNIPPET targeted back-end as a symbol.
-Translation, with `org-export-snippet-translation-alist', is
-applied."
- (let ((back-end (org-element-property :back-end export-snippet)))
- (intern
- (or (cdr (assoc back-end org-export-snippet-translation-alist))
- back-end))))
-
-
-;;;; For Footnotes
-;;
-;; `org-export-collect-footnote-definitions' is a tool to list
-;; actually used footnotes definitions in the whole parse tree, or in
-;; an headline, in order to add footnote listings throughout the
-;; transcoded data.
-;;
-;; `org-export-footnote-first-reference-p' is a predicate used by some
-;; back-ends, when they need to attach the footnote definition only to
-;; the first occurrence of the corresponding label.
-;;
-;; `org-export-get-footnote-definition' and
-;; `org-export-get-footnote-number' provide easier access to
-;; additional information relative to a footnote reference.
-
-(defun org-export-collect-footnote-definitions (data info)
- "Return an alist between footnote numbers, labels and definitions.
-
-DATA is the parse tree from which definitions are collected.
-INFO is the plist used as a communication channel.
-
-Definitions are sorted by order of references. They either
-appear as Org data or as a secondary string for inlined
-footnotes. Unreferenced definitions are ignored."
- (let* (num-alist
- collect-fn ; for byte-compiler.
- (collect-fn
- (function
- (lambda (data)
- ;; Collect footnote number, label and definition in DATA.
- (org-element-map
- data 'footnote-reference
- (lambda (fn)
- (when (org-export-footnote-first-reference-p fn info)
- (let ((def (org-export-get-footnote-definition fn info)))
- (push
- (list (org-export-get-footnote-number fn info)
- (org-element-property :label fn)
- def)
- num-alist)
- ;; Also search in definition for nested footnotes.
- (when (eq (org-element-property :type fn) 'standard)
- (funcall collect-fn def)))))
- ;; Don't enter footnote definitions since it will happen
- ;; when their first reference is found.
- info nil 'footnote-definition)))))
- (funcall collect-fn (plist-get info :parse-tree))
- (reverse num-alist)))
-
-(defun org-export-footnote-first-reference-p (footnote-reference info)
- "Non-nil when a footnote reference is the first one for its label.
-
-FOOTNOTE-REFERENCE is the footnote reference being considered.
-INFO is the plist used as a communication channel."
- (let ((label (org-element-property :label footnote-reference)))
- ;; Anonymous footnotes are always a first reference.
- (if (not label) t
- ;; Otherwise, return the first footnote with the same LABEL and
- ;; test if it is equal to FOOTNOTE-REFERENCE.
- (let* (search-refs ; for byte-compiler.
- (search-refs
- (function
- (lambda (data)
- (org-element-map
- data 'footnote-reference
- (lambda (fn)
- (cond
- ((string= (org-element-property :label fn) label)
- (throw 'exit fn))
- ;; If FN isn't inlined, be sure to traverse its
- ;; definition before resuming search. See
- ;; comments in `org-export-get-footnote-number'
- ;; for more information.
- ((eq (org-element-property :type fn) 'standard)
- (funcall search-refs
- (org-export-get-footnote-definition fn info)))))
- ;; Don't enter footnote definitions since it will
- ;; happen when their first reference is found.
- info 'first-match 'footnote-definition)))))
- (eq (catch 'exit (funcall search-refs (plist-get info :parse-tree)))
- footnote-reference)))))
-
-(defun org-export-get-footnote-definition (footnote-reference info)
- "Return definition of FOOTNOTE-REFERENCE as parsed data.
-INFO is the plist used as a communication channel."
- (let ((label (org-element-property :label footnote-reference)))
- (or (org-element-property :inline-definition footnote-reference)
- (cdr (assoc label (plist-get info :footnote-definition-alist))))))
-
-(defun org-export-get-footnote-number (footnote info)
- "Return number associated to a footnote.
-
-FOOTNOTE is either a footnote reference or a footnote definition.
-INFO is the plist used as a communication channel."
- (let* ((label (org-element-property :label footnote))
- seen-refs
- search-ref ; For byte-compiler.
- (search-ref
- (function
- (lambda (data)
- ;; Search footnote references through DATA, filling
- ;; SEEN-REFS along the way.
- (org-element-map
- data 'footnote-reference
- (lambda (fn)
- (let ((fn-lbl (org-element-property :label fn)))
- (cond
- ;; Anonymous footnote match: return number.
- ((and (not fn-lbl) (eq fn footnote))
- (throw 'exit (1+ (length seen-refs))))
- ;; Labels match: return number.
- ((and label (string= label fn-lbl))
- (throw 'exit (1+ (length seen-refs))))
- ;; Anonymous footnote: it's always a new one. Also,
- ;; be sure to return nil from the `cond' so
- ;; `first-match' doesn't get us out of the loop.
- ((not fn-lbl) (push 'inline seen-refs) nil)
- ;; Label not seen so far: add it so SEEN-REFS.
- ;;
- ;; Also search for subsequent references in
- ;; footnote definition so numbering follows reading
- ;; logic. Note that we don't have to care about
- ;; inline definitions, since `org-element-map'
- ;; already traverses them at the right time.
- ;;
- ;; Once again, return nil to stay in the loop.
- ((not (member fn-lbl seen-refs))
- (push fn-lbl seen-refs)
- (funcall search-ref
- (org-export-get-footnote-definition fn info))
- nil))))
- ;; Don't enter footnote definitions since it will happen
- ;; when their first reference is found.
- info 'first-match 'footnote-definition)))))
- (catch 'exit (funcall search-ref (plist-get info :parse-tree)))))
-
-
-;;;; For Headlines
-;;
-;; `org-export-get-relative-level' is a shortcut to get headline
-;; level, relatively to the lower headline level in the parsed tree.
-;;
-;; `org-export-get-headline-number' returns the section number of an
-;; headline, while `org-export-number-to-roman' allows to convert it
-;; to roman numbers.
-;;
-;; `org-export-low-level-p', `org-export-first-sibling-p' and
-;; `org-export-last-sibling-p' are three useful predicates when it
-;; comes to fulfill the `:headline-levels' property.
-
-(defun org-export-get-relative-level (headline info)
- "Return HEADLINE relative level within current parsed tree.
-INFO is a plist holding contextual information."
- (+ (org-element-property :level headline)
- (or (plist-get info :headline-offset) 0)))
-
-(defun org-export-low-level-p (headline info)
- "Non-nil when HEADLINE is considered as low level.
-
-INFO is a plist used as a communication channel.
-
-A low level headlines has a relative level greater than
-`:headline-levels' property value.
-
-Return value is the difference between HEADLINE relative level
-and the last level being considered as high enough, or nil."
- (let ((limit (plist-get info :headline-levels)))
- (when (wholenump limit)
- (let ((level (org-export-get-relative-level headline info)))
- (and (> 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. <<path>>) 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 "<<path>>" 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
diff --git a/contrib/lisp/org-favtable.el b/contrib/lisp/org-favtable.el
new file mode 100755
index 0000000..51f75a5
--- /dev/null
+++ b/contrib/lisp/org-favtable.el
@@ -0,0 +1,1701 @@
+;;; org-favtable.el --- Lookup table of favorite references and links
+
+;; Copyright (C) 2011-2013 Free Software Foundation, Inc.
+
+;; Author: Marc-Oliver Ihm <org-favtable@ferntreffer.de>
+;; Keywords: hypermedia, matching
+;; Requires: org
+;; Download: http://orgmode.org/worg/code/elisp/org-favtable.el
+;; Version: 2.2.0
+
+;; This file is not part of GNU Emacs.
+
+;;; License:
+
+;; 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, 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Purpose:
+;;
+;; Mark and find your favorite things and locations in org easily: Create
+;; and update a lookup table of your references and links. Often used
+;; entries bubble to the top and entering some keywords displays only the
+;; matching entries. That way the right entry one can be picked easily.
+;;
+;; References are essentially small numbers (e.g. "R237" or "-455-"),
+;; which are created by this package; they are well suited to be used
+;; outside of org. Links are just normal org-mode links.
+;;
+;;
+;; Setup:
+;;
+;; - Add these lines to your .emacs:
+;;
+;; (require 'org-favtable)
+;; ;; Good enough to start, but later you should probably
+;; ;; change this id, as will be explained below
+;; (setq org-favtable-id "00e26bef-1929-4110-b8b4-7eb9c9ab1fd4")
+;; ;; Optionally assign a key. Pick your own favorite.
+;; (global-set-key (kbd "C-+") 'org-favtable)
+;;
+;; - Just invoke `org-favtable', which will explain how to complete your
+;; setup by creating the necessary table of favorites.
+;;
+;;
+;; Further reading:
+;;
+;; Invoke `org-favtable' and pick one of its help options. You may also
+;; read the documentation of `org-favtable-id' for setup instructions, of
+;; `org-favtable' for regular usage and of `org-favtable--commands' for a
+;; list of available commands.
+;;
+
+;;; Change Log:
+
+;; [2013-02-28 Th] Version 2.2.0:
+;; - Allowed shortcuts like "h237" for command "head" with argument "237"
+;; - Integrated with org-mark-ring-goto
+;;
+;; [2013-01-25 Fr] Version 2.1.0:
+;; - Added full support for links
+;; - New commands "missing" and "statistics"
+;; - Renamed the package from "org-reftable" to "org-favtable"
+;; - Additional columns are required (e.g. "link"). Error messages will
+;; guide you
+;;
+;; [2012-12-07 Fr] Version 2.0.0:
+;; - The format of the table of favorites has changed ! You need to bring
+;; your existing table into the new format by hand (which however is
+;; easy and explained below)
+;; - Reference table can be sorted after usage count or date of last access
+;; - Ask user explicitly, which command to invoke
+;; - Renamed the package from "org-refer-by-number" to "org-reftable"
+
+;; [2012-09-22 Sa] Version 1.5.0:
+;; - New command "sort" to sort a buffer or region by reference number
+;; - New commands "highlight" and "unhighlight" to mark references
+
+;; [2012-07-13 Fr] Version 1.4.0:
+;; - New command "head" to find a headline with a reference number
+
+;; [2012-04-28 Sa] Version 1.3.0:
+;; - New commands occur and multi-occur
+;; - All commands can now be invoked explicitly
+;; - New documentation
+;; - Many bugfixes
+
+;; [2011-12-10 Sa] Version 1.2.0:
+;; - Fixed a bug, which lead to a loss of newly created reference numbers
+;; - Introduced single and double prefix arguments
+;; - Started this Change Log
+
+;;; Code:
+
+(require 'org-table)
+(require 'cl)
+
+(defvar org-favtable--version "2.2.0")
+(defvar org-favtable--preferred-command nil)
+
+(defvar org-favtable--commands '(occur head ref link enter leave goto + help reorder fill sort update highlight unhighlight missing statistics)
+ "List of commands known to org-favtable:
+
+Commands known:
+
+ occur: If you supply a keyword (text): Apply emacs standard
+ occur operation on the table of favorites; ask for a
+ string (keyword) to select lines. Occur will only show you
+ lines which contain the given keyword, so you can easily find
+ the right one. You may supply a list of words seperated by
+ comma (\",\"), to select lines that contain any or all of the
+ given words.
+
+ If you supply a reference number: Apply emacs standard
+ multi-occur operation all org-mode buffers to search for a
+ specific reference.
+
+ You may also read the note at the end of this help on saving
+ the keystroke RET to accept this frequent default command.
+
+ head: If invoked outside the table of favorites, ask for a
+ reference number and search for a heading containing it. If
+ invoked within favtable dont ask; rather use the reference or
+ link from the current line.
+
+ ref: Create a new reference, copy any previously selected text.
+ If already within reftable, fill in ref-column.
+
+ link: Create a new line in reftable with a link to the current node.
+ Do not populate the ref column; this can later be populated by
+ calling the \"fill\" command from within the reftable.
+
+ leave: Leave the table of favorites. If the last command has
+ been \"ref\", the new reference is copied and ready to yank.
+ This \"org-mark-ring-goto\" and can be called several times
+ in succession.
+
+ enter: Just enter the node with the table of favorites.
+
+ goto: Search for a specific reference within the table of
+ favorites.
+
+ help: Show this list of commands.
+
+ +: Show all commands including the less frequently used ones
+ given below. If \"+\" is followd by enough letters of such a
+ command (e.g. \"+fi\"), then this command is invoked
+ directly.
+
+ reorder: Temporarily reorder the table of favorites, e.g. by
+ count, reference or last access.
+
+ fill: If either ref or link is missing, fill it.
+
+ sort: Sort a set of lines (either the active region or the
+ whole buffer) by the references found in each line.
+
+ update: For the given reference, update the line in the
+ favtable.
+
+ highlight: Highlight references in region or buffer.
+
+ unhighlight: Remove highlights.
+
+ missing : Search for missing reference numbers (which do not
+ appear in the reference table). If requested, add additional
+ lines for them, so that the command \"new\" is able to reuse
+ them.
+
+ statistics : Show some statistics (e.g. minimum and maximum
+ reference) about favtable.
+
+
+
+Two ways to save keystrokes:
+
+When prompting for a command, org-favtable puts the most likely
+one (e.g. \"occur\" or \"ref\") at the front of the list, so that
+you may just type RET.
+
+If this command needs additional input (like e.g. \"occur\"), you
+may supply this input right away, although you are still beeing
+prompted for the command. So do an occur for the string \"foo\",
+you can just enter \"foo\" without even entering \"occur\".
+
+
+Another way to save keystrokes applies if you want to choose a
+command, that requrires a reference number (and would normally
+prompt for it): In that case you may just enter enough characters
+from your command, so that it appears first in the list of
+matches; then immediately enter the number of the reference you
+are searching for. So the input \"h237\" would execute the
+command \"head\" for reference \"237\" right away.
+
+")
+
+(defvar org-favtable--commands-some '(occur head ref link leave enter goto + help))
+
+(defvar org-favtable--columns nil)
+
+(defvar org-favtable-id nil
+ "Id of the Org-mode node, which contains the favorite table.
+
+Read below, on how to set up things. See the help options
+\"usage\" and \"commands\" for normal usage after setup.
+
+Setup requires two steps:
+
+ - Adjust your .emacs initialization file
+
+ - Create a suitable org-mode node
+
+
+Here are the lines, you need to add to your .emacs:
+
+ (require 'org-favtable)
+ ;; Good enough to start, but later you should probably
+ ;; change this id, as will be explained below
+ (setq org-favtable-id \"00e26bef-1929-4110-b8b4-7eb9c9ab1fd4\")
+ ;; Optionally assign a key. Pick your own favorite.
+ (global-set-key (kbd \"C-+\") 'org-favtable)
+
+Do not forget to restart emacs to make these lines effective.
+
+
+As a second step you need to create the org-mode node, where your
+reference numbers and links will be stored. It may look like
+this:
+
+ * org-favtable
+ :PROPERTIES:
+ :ID: 00e26bef-1929-4110-b8b4-7eb9c9ab1fd4
+ :END:
+
+
+ | | | Comment, description, details | | | |
+ | ref | link | ;c | count;s | created | last-accessed |
+ | | <4> | <30> | | | |
+ |-----+------+--------------------------------+---------+---------+---------------|
+ | R1 | | My first reference | | | |
+
+
+You may just copy this node into one of your org-files. Many
+things however can or should be adjusted:
+
+ - The node needs not be a top level node.
+
+ - Its name is completely at you choice. The node is found
+ through its ID.
+
+ - There are three lines of headings above the first hline. The
+ first one is ignored by org-favtable, and you can use them to
+ give meaningful names to columns; the second line contains
+ configuration information for org-favtable; please read
+ further below for its format. The third line is optional and
+ may contain width-informations (e.g. <30>) only.
+
+ - The sequence of columns does not matter. You may reorder them
+ any way you like; e.g. make the comment-column the last
+ columns within the table. Columns ar found by their name,
+ which appears in the second heading-line.
+
+ - You can add further columns or even remove the
+ \"Comment\"-column. All other columns from the
+ example (e.g. \"ref\", \"link\", \"count\", \"created\" and
+ \"last-accessed\") are required.
+
+ - Your references need not start at \"R1\"; However, having an
+ initial row is required (it serves as a template for subsequent
+ references).
+
+ - Your reference need not have the form \"R1\"; you may just as
+ well choose any text, that contains a single number,
+ e.g. \"reference-{1}\" or \"#7\" or \"++17++\" or \"-344-\". The
+ function `org-favtable' will inspect your first reference and
+ create all subsequent references in the same way.
+
+ - You may want to change the ID-Property of the node above and
+ create a new one, which is unique (and not just a copy of
+ mine). You need to change it in the lines copied to your .emacs
+ too. However, this is not strictly required to make things
+ work, so you may do this later, after trying out this package.
+
+
+Optionally you may tweak the second header line to adjust
+`org-favtable' a bit. In the example above it looks like this
+ (with spaces collapsed):
+
+
+ | ref | link | ;c | count;s | created | last-accessed |
+
+
+The different fields have different meanings:
+
+ - ref : This denotes the column which contains you references
+
+ - link : Column for org-mode links, which can be used to access
+ locations within your files.
+
+ - ;c : The flag \"c\" (\"c\" for \"copy\") denotes this column
+ as the one beeing copied on command \"leave\". In the example
+ above, it is also the comment-column.
+
+ - count;s : this is the column which counts, how many time this
+ line has been accessed (which is the key-feature of this
+ package). The flag \"s\" stands for \"sort\", so the table is
+ sorted after this column. You may also sort after columns
+ \"ref\" or \"last-accessed\".
+
+ - created : Date when this line was created.
+
+ - last-accessed : Date and time, when this line was last accessed.
+
+
+After this two-step setup process you may invoke `org-favtable'
+to create a new favorite. Read the help option \"usage\" for
+instructions on normal usage, read the help option \"commands\"
+for help on single commands.
+
+")
+
+
+(defvar org-favtable--text-to-yank nil)
+(defvar org-favtable--last-action nil)
+(defvar org-favtable--occur-buffer nil)
+(defvar org-favtable--ref-regex nil)
+(defvar org-favtable--ref-format nil)
+
+
+
+(defun org-favtable (&optional what search search-is-link)
+ "Mark and find your favorite items and org-locations easily:
+Create and update a lookup table of your favorite references and
+links. Often used entries automatically bubble to the top of the
+table; entering some keywords narrows it to just the matching
+entries; that way the right one can be picked easily.
+
+References are essentially small numbers (e.g. \"R237\" or
+\"-455-\"), as created by this package; links are normal org-mode
+links. Within org-favtable, both are denoted as favorites.
+
+
+Read below for a detailed description of this function. See the
+help option \"setup\" or read the documentation of
+`org-favtable-id' for setup instructions.
+
+The function `org-favtable' operates on a dedicated table (called
+the table or favorites or favtable, for short) within a special
+Org-mode node. The node has to be created as part of your initial
+setup. Each line of the favorite table contains:
+
+ - A reference (optional)
+
+ - A link (optional)
+
+ - A number; counting, how often each reference has been
+ used. This number is updated automatically and the table can
+ be sorted according to it, so that most frequently used
+ references appear at the top of the table and can be spotted
+ easily.
+
+ - Its respective creation date
+
+ - Date and time of last access. This column can alternatively be
+ used to sort the table.
+
+To be useful, your table of favorites should probably contain a
+column with comments too, which allows lines to be selected by
+keywords.
+
+The table of favorites is found through the id of the containing
+node; this id should be stored within `org-favtable-id' (see there
+for details).
+
+
+The function `org-favtable' is the only interactive function of
+this package and its sole entry point; it offers several commands
+to create, find and look up these favorites (references and
+links). All of them are explained within org-favtable's help.
+
+
+Finally, org-favtable can also be invoked from elisp; the two
+optional arguments accepted are:
+
+ search : string to search for
+ what : symbol of the command to invoke
+ search-is-link : t, if argument search is actually a link
+
+An example would be:
+
+ (org-favtable \"237\" 'head) ;; find heading with ref 237
+
+"
+
+ (interactive "P")
+
+ (let (within-node ; True, if we are within node with favtable
+ result-is-visible ; True, if node or occur is visible in any window
+ ref-node-buffer-and-point ; cons with buffer and point of favorites node
+ below-cursor ; word below cursor
+ active-region ; active region (if any)
+ link-id ; link of starting node, if required
+ guarded-search ; with guard against additional digits
+ search-is-ref ; true, if search is a reference
+ commands ; currently active set of selectable commands
+ what-adjusted ; True, if we had to adjust what
+ what-input ; Input on what question (need not necessary be "what")
+ reorder-once ; Column to use for single time sorting
+ parts ; Parts of a typical reference number (which
+ ; need not be a plain number); these are:
+ head ; Any header before number (e.g. "R")
+ maxref ; Maximum number from reference table (e.g. "153")
+ tail ; Tail after number (e.g. "}" or "")
+ ref-regex ; Regular expression to match a reference
+ has-reuse ; True, if table contains a line for reuse
+ numcols ; Number of columns in favtable
+ kill-new-text ; Text that will be appended to kill ring
+ message-text ; Text that will be issued as an explanation,
+ ; what we have done
+ initial-ref-or-link ; Initial position in reftable
+ )
+
+ ;;
+ ;; Examine current buffer and location, before turning to favtable
+ ;;
+
+ ;; Get the content of the active region or the word under cursor
+ (if (and transient-mark-mode
+ mark-active)
+ (setq active-region (buffer-substring (region-beginning) (region-end))))
+ (setq below-cursor (thing-at-point 'symbol))
+
+
+ ;; Find out, if we are within favable or not
+ (setq within-node (string= (org-id-get) org-favtable-id))
+
+ ;; Find out, if point in any window is within node with favtable
+ (mapc (lambda (x) (with-current-buffer (window-buffer x)
+ (when (or
+ (string= (org-id-get) org-favtable-id)
+ (eq (window-buffer x)
+ org-favtable--occur-buffer))
+ (setq result-is-visible t))))
+ (window-list))
+
+
+
+ ;;
+ ;; Get decoration of references and highest reference from favtable
+ ;;
+
+
+ ;; Save initial ref or link
+ (if (and within-node
+ (org-at-table-p))
+ (setq initial-ref-or-link
+ (or (org-favtable--get-field 'ref)
+ (org-favtable--get-field 'link))))
+
+ ;; Find node
+ (setq ref-node-buffer-and-point (org-favtable--id-find))
+ (unless ref-node-buffer-and-point
+ (org-favtable--report-setup-error
+ (format "Cannot find node with id \"%s\"" org-favtable-id)))
+
+ ;; Get configuration of reftable; catch errors
+ (let ((error-message
+ (catch 'content-error
+
+ (with-current-buffer (car ref-node-buffer-and-point)
+ (save-excursion
+ (unless (string= (org-id-get) org-favtable-id)
+ (goto-char (cdr ref-node-buffer-and-point)))
+
+ ;; parse table while still within buffer
+ (setq parts (org-favtable--parse-and-adjust-table)))
+
+ nil))))
+ (when error-message
+ (org-pop-to-buffer-same-window (car ref-node-buffer-and-point))
+ (org-reveal)
+ (error error-message)))
+
+ ;; Give names to parts of configuration
+ (setq head (nth 0 parts))
+ (setq maxref (nth 1 parts))
+ (setq tail (nth 2 parts))
+ (setq numcols (nth 3 parts))
+ (setq ref-regex (nth 4 parts))
+ (setq has-reuse (nth 5 parts))
+ (setq org-favtable--ref-regex ref-regex)
+ (setq org-favtable--ref-format (concat head "%d" tail))
+
+ ;;
+ ;; Find out, what we are supposed to do
+ ;;
+
+ (if (equal what '(4)) (setq what 'leave))
+
+ ;; Set preferred action, that will be the default choice
+ (setq org-favtable--preferred-command
+ (if within-node
+ (if (memq org-favtable--last-action '(ref link))
+ 'leave
+ 'occur)
+ (if active-region
+ 'ref
+ (if (and below-cursor (string-match ref-regex below-cursor))
+ 'occur
+ nil))))
+
+ ;; Ask user, what to do
+ (unless what
+ (setq commands (copy-list org-favtable--commands-some))
+ (while (progn
+ (setq what-input
+ (org-icompleting-read
+ "Please choose: "
+ (mapcar 'symbol-name
+ ;; Construct unique list of commands with
+ ;; preferred one at front
+ (delq nil (delete-dups
+ (append
+ (list org-favtable--preferred-command)
+ commands))))
+ nil nil))
+
+
+ ;; if input starts with "+", any command (not only some) may follow
+ ;; this allows input like "+sort" to be accepted
+ (when (string= (substring what-input 0 1) "+")
+ ;; make all commands available for selection
+ (setq commands (copy-list org-favtable--commands))
+ (unless (string= what-input "+")
+ ;; not just "+", use following string
+ (setq what-input (substring what-input 1))
+
+ (let ((completions
+ ;; get list of possible completions for what-input
+ (all-completions what-input (mapcar 'symbol-name commands))))
+ ;; use it, if unambigously
+ (if (= (length completions) 1)
+ (setq what-input (car completions))))))
+
+
+ ;; if input ends in digits, save them away and do completions on head of input
+ ;; this allows input like "h224" to be accepted
+ (when (string-match "^\\([^0-9+]\\)\\([0-9]+\\)\\s *$" what-input)
+ ;; use first match as input, even if ambigously
+ (setq org-favtable--preferred-command
+ (intern (first (all-completions (match-string 1 what-input)
+ (mapcar 'symbol-name commands)))))
+ ;; use digits as argument to commands
+ (setq what-input (format org-favtable--ref-format
+ (string-to-number (match-string 2 what-input)))))
+
+ (setq what (intern what-input))
+
+ ;; user is not required to input one of the commands; if
+ ;; not, take the first one and use the original input for
+ ;; next question
+ (if (memq what commands)
+ ;; input matched one element of list, dont need original
+ ;; input any more
+ (setq what-input nil)
+ ;; what-input will be used for next question, use first
+ ;; command for what
+ (setq what (or org-favtable--preferred-command
+ (first commands)))
+ ;; remove any trailing dot, that user might have added to
+ ;; disambiguate his input
+ (if (equal (substring what-input -1) ".")
+ ;; but do this only, if dot was really necessary to
+ ;; disambiguate
+ (let ((shortened-what-input (substring what-input 0 -1)))
+ (unless (test-completion shortened-what-input
+ (mapcar 'symbol-name
+ commands))
+ (setq what-input shortened-what-input)))))
+
+ ;; ask for reorder in loop, because we have to ask for
+ ;; what right again
+ (if (eq what 'reorder)
+ (setq reorder-once
+ (intern
+ (org-icompleting-read
+ "Please choose column to reorder reftable once: "
+ (mapcar 'symbol-name '(ref count last-accessed))
+ nil t))))
+
+ ;; maybe ask initial question again
+ (memq what '(reorder +)))))
+
+
+ ;;
+ ;; Get search, if required
+ ;;
+
+ ;; These actions need a search string:
+ (when (memq what '(goto occur head update))
+
+ ;; Maybe we've got a search string from the arguments
+ (unless search
+ (let (search-from-table
+ search-from-cursor)
+
+ ;; Search string can come from several sources:
+ ;; From ref column of table
+ (when within-node
+ (setq search-from-table (org-favtable--get-field 'ref)))
+ ;; From string below cursor
+ (when (and (not within-node)
+ below-cursor
+ (string-match (concat "\\(" ref-regex "\\)")
+ below-cursor))
+ (setq search-from-cursor (match-string 1 below-cursor)))
+
+ ;; Depending on requested action, get search from one of the sources above
+ (cond ((eq what 'goto)
+ (setq search (or what-input search-from-cursor)))
+ ((memq what '(head occur))
+ (setq search (or what-input search-from-table search-from-cursor))))))
+
+
+ ;; If we still do not have a search string, ask user explicitly
+ (unless search
+
+ (if what-input
+ (setq search what-input)
+ (setq search (read-from-minibuffer
+ (cond ((memq what '(occur head))
+ "Text or reference number to search for: ")
+ ((eq what 'goto)
+ "Reference number to search for, or enter \".\" for id of current node: ")
+ ((eq what 'update)
+ "Reference number to update: ")))))
+
+ (if (string-match "^\\s *[0-9]+\\s *$" search)
+ (setq search (format "%s%s%s" head (org-trim search) tail))))
+
+ ;; Clean up and examine search string
+ (if search (setq search (org-trim search)))
+ (if (string= search "") (setq search nil))
+ (setq search-is-ref (string-match ref-regex search))
+
+ ;; Check for special case
+ (when (and (memq what '(head goto))
+ (string= search "."))
+ (setq search (org-id-get))
+ (setq search-is-link t))
+
+ (when search-is-ref
+ (setq guarded-search (org-favtable--make-guarded-search search)))
+
+ ;;
+ ;; Do some sanity checking before really starting
+ ;;
+
+ ;; Correct requested action, if nothing to search
+ (when (and (not search)
+ (memq what '(search occur head)))
+ (setq what 'enter)
+ (setq what-adjusted t))
+
+ ;; For a proper reference as input, we do multi-occur
+ (if (and (string-match ref-regex search)
+ (eq what 'occur))
+ (setq what 'multi-occur))
+
+ ;; Check for invalid combinations of arguments; try to be helpful
+ (when (and (memq what '(head goto))
+ (not search-is-link)
+ (not search-is-ref))
+ (error "Can do '%s' only for a reference or link (not '%s'), try 'occur' to search for text" what search)))
+
+
+ ;;
+ ;; Prepare
+ ;;
+
+ ;; Get link if required before moving in
+ (if (eq what 'link)
+ (setq link-id (org-id-get-create)))
+
+ ;; Move into table, if outside
+ (when (memq what '(enter ref link goto occur multi-occur missing statistics))
+
+ ;; Support orgmode-standard of going back (buffer and position)
+ (org-mark-ring-push)
+
+ ;; Switch to favtable
+ (org-pop-to-buffer-same-window (car ref-node-buffer-and-point))
+ (goto-char (cdr ref-node-buffer-and-point))
+ (show-subtree)
+ (org-show-context)
+
+ ;; sort favtable
+ (org-favtable--sort-table reorder-once))
+
+ ;; Goto back to initial ref, because reformatting of table above might
+ ;; have moved point
+ (when initial-ref-or-link
+ (while (and (org-at-table-p)
+ (not (or
+ (string= initial-ref-or-link (org-favtable--get-field 'ref))
+ (string= initial-ref-or-link (org-favtable--get-field 'link)))))
+ (forward-line))
+ ;; did not find ref, go back to top
+ (if (not (org-at-table-p)) (goto-char top)))
+
+
+ ;;
+ ;; Actually do, what is requested
+ ;;
+
+ (cond
+
+
+ ((eq what 'help)
+
+ (let ((help-what
+ ;; which sort of help ?
+ (intern
+ (concat
+ "help-"
+ (org-icompleting-read
+ "Help on: "
+ (mapcar 'symbol-name '(commands usage setup version example))
+ nil t)))))
+
+ ;; help is taken from docstring of functions or variables
+ (cond ((eq help-what 'help-commands)
+ (org-favtable--show-help 'org-favtable--commands))
+ ((eq help-what 'help-usage)
+ (org-favtable--show-help 'org-favtable))
+ ((eq help-what 'help-setup)
+ (org-favtable--show-help 'org-favtable-id))
+ ((eq help-what 'help-version)
+ (org-favtable-version)))))
+
+
+ ((eq what 'multi-occur)
+
+ ;; Conveniently position cursor on number to search for
+ (org-favtable--goto-top)
+ (let (found (initial (point)))
+ (while (and (not found)
+ (forward-line)
+ (org-at-table-p))
+ (save-excursion
+ (setq found (string= search
+ (org-favtable--get-field 'ref)))))
+ (if found
+ (org-favtable--update-line nil)
+ (goto-char initial)))
+
+ ;; Construct list of all org-buffers
+ (let (buff org-buffers)
+ (dolist (buff (buffer-list))
+ (set-buffer buff)
+ (if (string= major-mode "org-mode")
+ (setq org-buffers (cons buff org-buffers))))
+
+ ;; Do multi-occur
+ (multi-occur org-buffers guarded-search)
+ (if (get-buffer "*Occur*")
+ (progn
+ (setq message-text (format "multi-occur for '%s'" search))
+ (setq org-favtable--occur-buffer (get-buffer "*Occur*"))
+ (other-window 1)
+ (toggle-truncate-lines 1))
+ (setq message-text (format "Did not find '%s'" search)))))
+
+
+ ((eq what 'head)
+
+ (let (link)
+ ;; link either from table or passed in as argument
+
+ ;; try to get link
+ (if search-is-link
+ (setq link (org-trim search))
+ (if (and within-node
+ (org-at-table-p))
+ (setq link (org-favtable--get-field 'link))))
+
+ ;; use link if available
+ (if (and link
+ (not (string= link "")))
+ (progn
+ (org-id-goto link)
+ (org-favtable--update-line search)
+ (setq message-text "Followed link"))
+
+ (message (format "Scanning headlines for '%s' ..." search))
+ (let (buffer point)
+ (if (catch 'found
+ (progn
+ ;; loop over all headlines, stop on first match
+ (org-map-entries
+ (lambda ()
+ (when (looking-at (concat ".*" guarded-search))
+ ;; remember location and bail out
+ (setq buffer (current-buffer))
+ (setq point (point))
+ (throw 'found t)))
+ nil 'agenda)
+ nil))
+
+ (progn
+ (org-favtable--update-line search)
+ (setq message-text (format "Found '%s'" search))
+ (org-pop-to-buffer-same-window buffer)
+ (goto-char point)
+ (org-reveal))
+ (setq message-text (format "Did not find '%s'" search)))))))
+
+
+ ((eq what 'leave)
+
+ (when result-is-visible
+
+ ;; If we are within the occur-buffer, switch over to get current line
+ (if (and (string= (buffer-name) "*Occur*")
+ (eq org-favtable--last-action 'occur))
+ (occur-mode-goto-occurrence)))
+
+ (setq kill-new-text org-favtable--text-to-yank)
+ (setq org-favtable--text-to-yank nil)
+
+ ;; If "leave" has been called two times in succession, make
+ ;; org-mark-ring-goto believe it has been called two times too
+ (if (eq org-favtable--last-action 'leave)
+ (let ((this-command nil) (last-command nil))
+ (org-mark-ring-goto 1))
+ (org-mark-ring-goto 0)))
+
+
+ ((eq what 'goto)
+
+ ;; Go downward in table to requested reference
+ (let (found (initial (point)))
+ (org-favtable--goto-top)
+ (while (and (not found)
+ (forward-line)
+ (org-at-table-p))
+ (save-excursion
+ (setq found
+ (string= search
+ (org-favtable--get-field
+ (if search-is-link 'link 'ref))))))
+ (if found
+ (progn
+ (setq message-text (format "Found '%s'" search))
+ (org-favtable--update-line nil)
+ (org-table-goto-column (org-favtable--column-num 'ref))
+ (if (looking-back " ") (backward-char))
+ ;; remember string to copy
+ (setq org-favtable--text-to-yank
+ (org-trim (org-table-get-field (org-favtable--column-num 'copy)))))
+ (setq message-text (format "Did not find '%s'" search))
+ (goto-char initial)
+ (forward-line)
+ (setq what 'missed))))
+
+
+ ((eq what 'occur)
+
+ ;; search for string: occur
+ (let (search-regexp
+ all-or-any
+ (search-words (split-string search "," t)))
+
+ (if (< (length search-words) 2)
+ ;; only one word to search; use it as is
+ (setq search-regexp search)
+ ;; construct regexp to match any of the words (maybe throw out some matches later)
+ (setq search-regexp
+ (mapconcat (lambda (x) (concat "\\(" x "\\)")) search-words "\\|"))
+ (setq all-or-any
+ (intern
+ (org-icompleting-read
+ "Two or more words have been specified; show lines, that match: " '("all" "any")))))
+
+ (save-restriction
+ (org-narrow-to-subtree)
+ (occur search-regexp)
+ (widen)
+ (if (get-buffer "*Occur*")
+ (with-current-buffer "*Occur*"
+
+ ;; install helpful keyboard-shortcuts within occur-buffer
+ (let ((keymap (make-sparse-keymap)))
+ (set-keymap-parent keymap occur-mode-map)
+
+ (define-key keymap (kbd "RET")
+ (lambda () (interactive)
+ (org-favtable--occur-helper 'head)))
+
+ (define-key keymap (kbd "<C-return>")
+ (lambda () (interactive)
+ (org-favtable--occur-helper 'multi-occur)))
+
+ (define-key keymap (kbd "<M-return>")
+ (lambda () (interactive)
+ (org-favtable--occur-helper 'goto)))
+
+ (define-key keymap (kbd "<C-M-return>")
+ (lambda () (interactive)
+ (org-favtable--occur-helper 'update)))
+
+ (use-local-map keymap))
+
+ ;; Brush up occur buffer
+ (other-window 1)
+ (toggle-truncate-lines 1)
+ (let ((inhibit-read-only t))
+ ;; insert some help text
+ (insert (substitute-command-keys
+ "Type RET to find heading, C-RET for multi-occur, M-RET to go to occurence and C-M-RET to update line in reftable.\n\n"))
+ (forward-line 1)
+
+ ;; when matching all of multiple words, remove all lines that do not match one of the words
+ (when (eq all-or-any 'all)
+ (mapc (lambda (x) (keep-lines x)) search-words))
+
+ ;; replace description from occur
+ (when all-or-any
+ (forward-line -1)
+ (kill-line)
+ (let ((count (- (count-lines (point) (point-max)) 1)))
+ (insert (format "%d %s for %s of %s"
+ count
+ (if (= count 1) "match" "matches")
+ all-or-any
+ search)))
+ (forward-line)
+ (beginning-of-line))
+
+ ;; Record link or reference for each line in
+ ;; occur-buffer, that is linked into reftable. Because if
+ ;; we later realign the reftable and then reuse the occur
+ ;; buffer, the original links might point nowehere.
+ (save-excursion
+ (while (not (eq (point) (point-max)))
+ (let ((beg (line-beginning-position))
+ (end (line-end-position))
+ pos ref link)
+
+ ;; occur has saved the position into a special property
+ (setq pos (get-text-property (point) 'occur-target))
+ (when pos
+ ;; but this property might soon point nowhere; so retrieve ref-or-link instead
+ (with-current-buffer (marker-buffer pos)
+ (goto-char pos)
+ (setq ref (org-favtable--get-field 'ref))
+ (setq link (org-favtable--get-field 'link))))
+ ;; save as text property
+ (put-text-property beg end 'org-favtable--ref ref)
+ (put-text-property beg end 'org-favtable--link link))
+ (forward-line))))
+
+ (setq message-text
+ (format "Occur for '%s'" search)))
+ (setq message-text
+ (format "Did not find any matches for '%s'" search))))))
+
+
+ ((memq what '(ref link))
+
+ ;; add a new row (or reuse existing one)
+ (let (new)
+
+ (when (eq what 'ref)
+ ;; go through table to find first entry to be reused
+ (when has-reuse
+ (org-favtable--goto-top)
+ ;; go through table
+ (while (and (org-at-table-p)
+ (not new))
+ (when (string=
+ (org-favtable--get-field 'count)
+ ":reuse:")
+ (setq new (org-favtable--get-field 'ref))
+ (if new (org-table-kill-row)))
+ (forward-line)))
+
+ ;; no ref to reuse; construct new reference
+ (unless new
+ (setq new (format "%s%d%s" head (1+ maxref) tail)))
+
+ ;; remember for org-mark-ring-goto
+ (setq org-favtable--text-to-yank new))
+
+ ;; insert ref or link as very first row
+ (org-favtable--goto-top)
+ (org-table-insert-row)
+
+ ;; fill special columns with standard values
+ (when (eq what 'ref)
+ (org-table-goto-column (org-favtable--column-num 'ref))
+ (insert new))
+ (when (eq what 'link)
+ (org-table-goto-column (org-favtable--column-num 'link))
+ (insert link-id))
+ (org-table-goto-column (org-favtable--column-num 'created))
+ (org-insert-time-stamp nil nil t)
+
+ ;; goto first empty field
+ (unless (catch 'empty
+ (dotimes (col numcols)
+ (org-table-goto-column (+ col 1))
+ (if (string= (org-trim (org-table-get-field)) "")
+ (throw 'empty t))))
+ ;; none found, goto first
+ (org-table-goto-column 1))
+
+ (org-table-align)
+ (if active-region (setq kill-new-text active-region))
+ (if (eq what 'ref)
+ (setq message-text (format "Adding a new row with ref '%s'" new))
+ (setq message-text (format "Adding a new row linked to '%s'" link-id)))))
+
+
+ ((eq what 'enter)
+
+ ;; simply go into table
+ (org-favtable--goto-top)
+ (show-subtree)
+ (recenter)
+ (if what-adjusted
+ (setq message-text "Nothing to search for; at favtable")
+ (setq message-text "At favtable")))
+
+
+ ((eq what 'fill)
+
+ ;; check, if within reftable
+ (unless (and within-node
+ (org-at-table-p))
+ (error "Not within table of favorites"))
+
+ ;; applies to missing refs and missing links alike
+ (let ((ref (org-favtable--get-field 'ref))
+ (link (org-favtable--get-field 'link)))
+
+ (if (and (not ref)
+ (not link))
+ ;; have already checked this during parse, check here anyway
+ (error "Columns ref and link are both empty in this line"))
+
+ ;; fill in new ref
+ (if (not ref)
+ (progn
+ (setq kill-new-text (format "%s%d%s" head (1+ maxref) tail))
+ (org-favtable--get-field 'ref kill-new-text)
+ ;; remember for org-mark-ring-goto
+ (setq org-favtable--text-to-yank kill-new-text)
+ (org-id-goto link)
+ (setq message-text "Filled reftable field with new reference"))
+
+ ;; fill in new link
+ (if (not link)
+ (progn
+ (setq guarded-search (org-favtable--make-guarded-search ref))
+ (message (format "Scanning headlines for '%s' ..." ref))
+ (let (link)
+ (if (catch 'found
+ (org-map-entries
+ (lambda ()
+ (when (looking-at (concat ".*" guarded-search))
+ (setq link (org-id-get-create))
+ (throw 'found t)))
+ nil 'agenda)
+ nil)
+
+ (progn
+ (org-favtable--get-field 'link link)
+ (setq message-text "Inserted link"))
+
+ (setq message-text (format "Did not find reference '%s'" ref)))))
+
+ ;; nothing is missing
+ (setq message-text "Columns 'ref' and 'link' are already filled; nothing to do")))))
+
+
+ ((eq what 'sort)
+
+ ;; sort lines according to contained reference
+ (let (begin end where)
+ (catch 'aborted
+ ;; either active region or whole buffer
+ (if (and transient-mark-mode
+ mark-active)
+ ;; sort only region
+ (progn
+ (setq begin (region-beginning))
+ (setq end (region-end))
+ (setq where "region"))
+ ;; sort whole buffer
+ (setq begin (point-min))
+ (setq end (point-max))
+ (setq where "whole buffer")
+ ;; make sure
+ (unless (y-or-n-p "Sort whole buffer ")
+ (setq message-text "Sort aborted")
+ (throw 'aborted nil)))
+
+ (save-excursion
+ (save-restriction
+ (goto-char (point-min))
+ (narrow-to-region begin end)
+ (sort-subr nil 'forward-line 'end-of-line
+ (lambda ()
+ (if (looking-at (concat ".*"
+ (org-favtable--make-guarded-search ref-regex 'dont-quote)))
+ (string-to-number (match-string 1))
+ 0))))
+ (highlight-regexp ref-regex)
+ (setq message-text (format "Sorted %s from character %d to %d, %d lines"
+ where begin end
+ (count-lines begin end)))))))
+
+
+ ((eq what 'update)
+
+ ;; simply update line in reftable
+ (save-excursion
+ (let ((ref-or-link (if search-is-link "link" "reference")))
+ (beginning-of-line)
+ (if (org-favtable--update-line search)
+ (setq message-text (format "Updated %s '%s'" ref-or-link search))
+ (setq message-text (format "Did not find %s '%s'" ref-or-link search))))))
+
+
+ ((eq what 'parse)
+
+ ;; Just parse the reftable, which is already done, so nothing to do
+ )
+
+
+ ((memq what '(highlight unhighlight))
+
+ (let ((where "buffer"))
+ (save-excursion
+ (save-restriction
+ (when (and transient-mark-mode
+ mark-active)
+ (narrow-to-region (region-beginning) (region-end))
+ (setq where "region"))
+
+ (if (eq what 'highlight)
+ (progn
+ (highlight-regexp ref-regex)
+ (setq message-text (format "Highlighted references in %s" where)))
+ (unhighlight-regexp ref-regex)
+ (setq message-text (format "Removed highlights for references in %s" where)))))))
+
+
+ ((memq what '(missing statistics))
+
+ (org-favtable--goto-top)
+ (let (missing
+ ref-field
+ ref
+ min
+ max
+ (total 0))
+
+ ;; start with list of all references
+ (setq missing (mapcar (lambda (x) (format "%s%d%s" head x tail))
+ (number-sequence 1 maxref)))
+
+ ;; go through table and remove all refs, that we see
+ (while (and (forward-line)
+ (org-at-table-p))
+
+ ;; get ref-field and number
+ (setq ref-field (org-favtable--get-field 'ref))
+ (if (and ref-field
+ (string-match ref-regex ref-field))
+ (setq ref (string-to-number (match-string 1 ref-field))))
+
+ ;; remove existing refs from list
+ (if ref-field (setq missing (delete ref-field missing)))
+
+ ;; record min and max
+ (if (or (not min) (< ref min)) (setq min ref))
+ (if (or (not max) (> ref max)) (setq max ref))
+
+ ;; count
+ (setq total (1+ total)))
+
+ ;; insert them, if requested
+ (forward-line -1)
+ (if (eq what 'statistics)
+
+ (setq message-text (format "Found %d references from %s to %s. %d references below highest do not appear in table. "
+ total
+ (format org-favtable--format min)
+ (format org-favtable--format max)
+ (length missing)))
+
+ (if (y-or-n-p (format "Found %d missing references; do you wish to append them to the table of favorites"
+ (length missing)))
+ (let (type)
+ (setq type (org-icompleting-read
+ "Insert new lines for reuse by command \"new\" or just as missing ? " '("reuse" "missing")))
+ (mapc (lambda (x)
+ (let (org-table-may-need-update) (org-table-insert-row t))
+ (org-favtable--get-field 'ref x)
+ (org-favtable--get-field 'count (format ":%s:" type)))
+ missing)
+ (org-table-align)
+ (setq message-text (format "Inserted %d new lines for missing refernces" (length missing))))
+ (setq message-text (format "%d missing references." (length missing)))))))
+
+
+ (t (error "This is a bug: unmatched case '%s'" what)))
+
+
+ ;; remember what we have done for next time
+ (setq org-favtable--last-action what)
+
+ ;; tell, what we have done and what can be yanked
+ (if kill-new-text (setq kill-new-text
+ (substring-no-properties kill-new-text)))
+ (if (string= kill-new-text "") (setq kill-new-text nil))
+ (let ((m (concat
+ message-text
+ (if (and message-text kill-new-text)
+ " and r"
+ (if kill-new-text "R" ""))
+ (if kill-new-text (format "eady to yank '%s'" kill-new-text) ""))))
+ (unless (string= m "") (message m)))
+ (if kill-new-text (kill-new kill-new-text))))
+
+
+
+(defun org-favtable--parse-and-adjust-table ()
+
+ (let ((maxref 0)
+ top
+ bottom
+ ref-field
+ link-field
+ parts
+ numcols
+ head
+ tail
+ ref-regex
+ has-reuse
+ initial-point)
+
+ (setq initial-point (point))
+ (org-favtable--goto-top)
+ (setq top (point))
+
+ (goto-char top)
+
+ ;; count columns
+ (org-table-goto-column 100)
+ (setq numcols (- (org-table-current-column) 1))
+
+ ;; get contents of columns
+ (forward-line -2)
+ (unless (org-at-table-p)
+ (org-favtable--report-setup-error
+ "Table of favorites starts with a hline" t))
+
+ ;; check for optional line consisting solely of width specifications
+ (beginning-of-line)
+ (if (looking-at "\\s *|\\(\\(\\s *|\\)\\|\\(\\s *<[0-9]+>\\s *|\\)\\)+\\s *$")
+ (forward-line -1))
+ (org-table-goto-column 1)
+
+ (setq org-favtable--columns (org-favtable--parse-headings numcols))
+
+ ;; Go beyond end of table
+ (while (org-at-table-p) (forward-line 1))
+
+ ;; Kill all empty rows at bottom
+ (while (progn
+ (forward-line -1)
+ (org-table-goto-column 1)
+ (and
+ (not (org-favtable--get-field 'ref))
+ (not (org-favtable--get-field 'link))))
+ (org-table-kill-row))
+ (forward-line)
+ (setq bottom (point))
+ (forward-line -1)
+
+ ;; Retrieve any decorations around the number within the first nonempty ref-field
+ (goto-char top)
+ (while (and (org-at-table-p)
+ (not (setq ref-field (org-favtable--get-field 'ref))))
+ (forward-line))
+
+ ;; Some Checking
+ (unless ref-field
+ (org-favtable--report-setup-error
+ "No line of reference column contains a number" t))
+
+ (unless (string-match "^\\([^0-9]*\\)\\([0-9]+\\)\\([^0-9]*\\)$" ref-field)
+ (org-favtable--report-setup-error
+ (format "First reference in table table of favorites ('%s') does not contain a number" ref-field) t))
+
+
+ ;; These are the decorations used within the first ref of favtable
+ (setq head (match-string 1 ref-field))
+ (setq tail (match-string 3 ref-field))
+ (setq ref-regex (concat (regexp-quote head)
+ "\\([0-9]+\\)"
+ (regexp-quote tail)))
+
+ ;; Go through table to find maximum number and do some checking
+ (let ((ref 0))
+
+ (while (org-at-table-p)
+
+ (setq ref-field (org-favtable--get-field 'ref))
+ (setq link-field (org-favtable--get-field 'link))
+
+ (if (and (not ref-field)
+ (not link-field))
+ (throw 'content-error "Columns ref and link are both empty in this line"))
+
+ (if ref-field
+ (if (string-match ref-regex ref-field)
+ ;; grab number
+ (setq ref (string-to-number (match-string 1 ref-field)))
+ (throw 'content-error "Column ref does not contain a number")))
+
+ ;; check, if higher ref
+ (if (> ref maxref) (setq maxref ref))
+
+ ;; check if ref is ment for reuse
+ (if (string= (org-favtable--get-field 'count) ":reuse:")
+ (setq has-reuse 1))
+
+ (forward-line 1)))
+
+ ;; sort used to be here
+
+ (setq parts (list head maxref tail numcols ref-regex has-reuse))
+
+ ;; go back to top of table
+ (goto-char top)
+
+ parts))
+
+
+
+(defun org-favtable--sort-table (sort-column)
+
+ (unless sort-column (setq sort-column (org-favtable--column-num 'sort)))
+
+ (let (top
+ bottom
+ ref-field
+ count-field
+ count-special)
+
+
+ ;; get boundaries of table
+ (org-favtable--goto-top)
+ (forward-line 0)
+ (setq top (point))
+ (while (org-at-table-p) (forward-line))
+ (setq bottom (point))
+
+ (save-restriction
+ (narrow-to-region top bottom)
+ (goto-char top)
+ (sort-subr t
+ 'forward-line
+ 'end-of-line
+ (lambda ()
+ (let (ref
+ (ref-field (or (org-favtable--get-field 'ref) ""))
+ (count-field (or (org-favtable--get-field 'count) ""))
+ (count-special 0))
+
+ ;; get reference with leading zeroes, so it can be
+ ;; sorted as text
+ (string-match org-favtable--ref-regex ref-field)
+ (setq ref (format
+ "%06d"
+ (string-to-number
+ (or (match-string 1 ref-field)
+ "0"))))
+
+ ;; find out, if special token in count-column
+ (setq count-special (format "%d"
+ (- 2
+ (length (member count-field '(":missing:" ":reuse:"))))))
+
+ ;; Construct different sort-keys according to
+ ;; requested sort column; prepend count-special to
+ ;; sort special entries at bottom of table, append ref
+ ;; as a secondary sort key
+ (cond
+
+ ((eq sort-column 'count)
+ (concat count-special
+ (format
+ "%08d"
+ (string-to-number (or (org-favtable--get-field 'count)
+ "")))
+ ref))
+
+ ((eq sort-column 'last-accessed)
+ (concat count-special
+ (org-favtable--get-field 'last-accessed)
+ " "
+ ref))
+
+ ((eq sort-column 'ref)
+ (concat count-special
+ ref))
+
+ (t (error "This is a bug: unmatched case '%s'" sort-column)))))
+
+ nil 'string<)))
+
+ ;; align table
+ (org-table-align))
+
+
+(defun org-favtable--goto-top ()
+
+ ;; go to heading of node
+ (while (not (org-at-heading-p)) (forward-line -1))
+ (forward-line 1)
+ ;; go to table within node, but make sure we do not get into another node
+ (while (and (not (org-at-heading-p))
+ (not (org-at-table-p))
+ (not (eq (point) (point-max))))
+ (forward-line 1))
+
+ ;; check, if there really is a table
+ (unless (org-at-table-p)
+ (org-favtable--report-setup-error
+ (format "Cannot find favtable within node %s" org-favtable-id) t))
+
+ ;; go to first hline
+ (while (and (not (org-at-table-hline-p))
+ (org-at-table-p))
+ (forward-line 1))
+
+ ;; and check
+ (unless (org-at-table-hline-p)
+ (org-favtable--report-setup-error
+ "Cannot find hline within table of favorites" t))
+
+ (forward-line 1)
+ (org-table-goto-column 1))
+
+
+
+(defun org-favtable--id-find ()
+ "Find org-favtable-id"
+ (let ((marker (org-id-find org-favtable-id 'marker))
+ marker-and-buffer)
+
+ (if marker
+ (progn
+ (setq marker-and-buffer (cons (marker-buffer marker) (marker-position marker)))
+ (move-marker marker nil)
+ marker-and-buffer)
+ nil)))
+
+
+
+(defun org-favtable--parse-headings (numcols)
+
+ (let (columns)
+
+ ;; Associate names of special columns with column-numbers
+ (setq columns (copy-tree '((ref . 0) (link . 0) (created . 0) (last-accessed . 0)
+ (count . 0) (sort . nil) (copy . nil))))
+
+ ;; For each column
+ (dotimes (col numcols)
+ (let* (field-flags ;; raw heading, consisting of file name and maybe
+ ;; flags (seperated by ";")
+ field ;; field name only
+ field-symbol ;; and as a symbol
+ flags ;; flags from field-flags
+ found)
+
+ ;; parse field-flags into field and flags
+ (setq field-flags (org-trim (org-table-get-field (+ col 1))))
+ (if (string-match "^\\([^;]*\\);\\([a-z]+\\)$" field-flags)
+ (progn
+ (setq field (downcase (or (match-string 1 field-flags) "")))
+ ;; get flags as list of characters
+ (setq flags (mapcar 'string-to-char
+ (split-string
+ (downcase (match-string 2 field-flags))
+ "" t))))
+ ;; no flags
+ (setq field field-flags))
+
+ (unless (string= field "") (setq field-symbol (intern (downcase field))))
+
+ ;; Check, that no flags appear twice
+ (mapc (lambda (x)
+ (when (memq (car x) flags)
+ (if (cdr (assoc (cdr x) columns))
+ (org-favtable--report-setup-error
+ (format "More than one heading is marked with flag '%c'" (car x)) t))))
+ '((?s . sort)
+ (?c . copy)))
+
+ ;; Process flags
+ (if (memq ?s flags)
+ (setcdr (assoc 'sort columns) field-symbol))
+ (if (memq ?c flags)
+ (setcdr (assoc 'copy columns) (+ col 1)))
+
+ ;; Store columns in alist
+ (setq found (assoc field-symbol columns))
+ (when found
+ (if (> (cdr found) 0)
+ (org-favtable--report-setup-error
+ (format "'%s' appears two times as column heading" (downcase field)) t))
+ (setcdr found (+ col 1)))))
+
+ ;; check if all necessary informations have been specified
+ (mapc (lambda (col)
+ (unless (> (cdr (assoc col columns)) 0)
+ (org-favtable--report-setup-error
+ (format "column '%s' has not been set" col) t)))
+ '(ref link count created last-accessed))
+
+ ;; use ref as a default sort-column
+ (unless (cdr (assoc 'sort columns))
+ (setcdr (assoc 'sort columns) 'ref))
+ columns))
+
+
+
+(defun org-favtable--report-setup-error (text &optional switch-to-node)
+
+ (when switch-to-node
+ (org-id-goto org-favtable-id)
+ (delete-other-windows))
+
+ (when (y-or-n-p (concat
+ text
+ ";\n"
+ "the correct setup is explained in the documentation of 'org-favtable-id'.\n"
+ "Do you want to read it ? "))
+ (org-favtable--show-help 'org-favtable-id))
+
+ (error "")
+ (setq org-favtable--last-action 'leave))
+
+
+
+(defun org-favtable--show-help (function-or-variable)
+
+ (let ((isfun (functionp function-or-variable)))
+ ;; bring up help-buffer for function or variable
+ (if isfun
+ (describe-function function-or-variable)
+ (describe-variable function-or-variable))
+
+
+ ;; clean up help-buffer
+ (pop-to-buffer "*Help*")
+ (let ((inhibit-read-only t))
+ (goto-char (point-min))
+ (while (progn
+ (kill-line 1)
+ (not (looking-at
+ (if isfun
+ "("
+ "Documentation:")))))
+ (kill-line (if isfun 2 3))
+ (goto-char (point-max))
+ (kill-line -2)
+ (goto-char (point-min)))))
+
+
+
+(defun org-favtable--update-line (ref-or-link)
+
+ (let (initial
+ found
+ count-field
+ (ref-node-buffer-and-point (org-favtable--id-find)))
+
+ (with-current-buffer (car ref-node-buffer-and-point)
+
+ ;; search reference or link, if given (or assume, that we are already positioned right)
+ (when ref-or-link
+ (setq initial (point))
+ (goto-char (cdr ref-node-buffer-and-point))
+ (org-favtable--goto-top)
+ (while (and (org-at-table-p)
+ (not (or (string= ref-or-link (org-favtable--get-field 'ref))
+ (string= ref-or-link (org-favtable--get-field 'link)))))
+ (forward-line)))
+
+ (if (not (org-at-table-p))
+ (error "Did not find reference or link '%s'" ref-or-link)
+ (setq count-field (org-favtable--get-field 'count))
+
+ ;; update count field only if number or empty; leave :missing: and :reuse: as is
+ (if (or (not count-field)
+ (string-match "^[0-9]+$" count-field))
+ (org-favtable--get-field 'count
+ (number-to-string
+ (+ 1 (string-to-number (or count-field "0"))))))
+
+ ;; update timestamp
+ (org-table-goto-column (org-favtable--column-num 'last-accessed))
+ (org-table-blank-field)
+ (org-insert-time-stamp nil t t)
+
+ (setq found t))
+
+ (if initial (goto-char initial))
+
+ found)))
+
+
+
+(defun org-favtable--occur-helper (action)
+ (let ((line-beg (line-beginning-position))
+ key search link ref)
+
+ ;; extract reference or link from text property (as put there before)
+ (setq ref (get-text-property line-beg 'org-favtable--ref))
+ (if (string= ref "") (setq ref nil))
+ (setq link (get-text-property line-beg 'org-favtable--link))
+ (if (string= link "") (setq link nil))
+
+ (org-favtable action
+ (or link ref) ;; prefer link
+ (if link t nil))))
+
+
+(defun org-favtable--get-field (key &optional value)
+ (let (field)
+ (setq field (org-trim (org-table-get-field (cdr (assoc key org-favtable--columns)) value)))
+ (if (string= field "") (setq field nil))
+
+ field))
+
+
+(defun org-favtable--column-num (key)
+ (cdr (assoc key org-favtable--columns)))
+
+
+(defun org-favtable-version ()
+ "Show version of org-favtable" (interactive)
+ (message "org-favtable %s" org-favtable--version))
+
+
+(defun org-favtable--make-guarded-search (ref &optional dont-quote)
+ (concat "\\b" (if dont-quote ref (regexp-quote ref)) "\\b"))
+
+
+(defun org-favtable-get-ref-regex-format ()
+ "return cons-cell with regular expression and format for references"
+ (unless org-favtable--ref-regex
+ (org-favtable 'parse))
+ (cons (org-favtable--make-guarded-search org-favtable--ref-regex 'dont-quote) org-favtable--ref-format))
+
+
+(defadvice org-mark-ring-goto (after org-favtable--advice-text-to-yank activate)
+ "Make text from the favtable available for yank."
+ (when org-favtable--text-to-yank
+ (kill-new org-favtable--text-to-yank)
+ (message (format "Ready to yank '%s'" org-favtable--text-to-yank))
+ (setq org-favtable--text-to-yank nil)))
+
+
+(provide 'org-favtable)
+
+;; Local Variables:
+;; fill-column: 75
+;; comment-column: 50
+;; End:
+
+;;; org-favtable.el ends here
diff --git a/contrib/lisp/org-git-link.el b/contrib/lisp/org-git-link.el
index 8223712..b9e6a4e 100644
--- a/contrib/lisp/org-git-link.el
+++ b/contrib/lisp/org-git-link.el
@@ -1,10 +1,12 @@
;;; org-git-link.el --- Provide org links to specific file version
-;; Copyright (C) 2009-2012 Reimar Finken
+;; Copyright (C) 2009-2013 Reimar Finken
;; Author: Reimar Finken <reimar.finken@gmx.de>
;; Keywords: files, calendar, hypermedia
+;; This file is not part of GNU Emacs.
+
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
@@ -130,10 +132,11 @@
(list (expand-file-name ".git" dir) relpath))))
-(if (featurep 'xemacs)
- (defalias 'org-git-gitrepos-p 'org-git-find-gitdir)
- (defalias 'org-git-gitrepos-p 'org-git-find-gitdir
- "Return non-nil if path is in git repository"))
+(eval-and-compile
+ (if (featurep 'xemacs)
+ (defalias 'org-git-gitrepos-p 'org-git-find-gitdir)
+ (defalias 'org-git-gitrepos-p 'org-git-find-gitdir
+ "Return non-nil if path is in git repository")))
;; splitting the link string
@@ -171,7 +174,7 @@
(let* ((gitdir (first (org-git-find-gitdir (file-truename file))))
(branchname (org-git-get-current-branch gitdir))
(timestring (format-time-string "%Y-%m-%d" (current-time))))
- (contact "git:" file "::" (org-git-create-searchstring branchname timestring))))
+ (concat "git:" file "::" (org-git-create-searchstring branchname timestring))))
(defun org-git-store-link ()
"Store git link to current file."
@@ -194,8 +197,7 @@
(unless
(zerop (call-process org-git-program nil buffer nil
"--no-pager" (concat "--git-dir=" gitdir) "show" object))
- (error "git error: %s " (save-excursion (set-buffer buffer)
- (buffer-string)))))
+ (error "git error: %s " (with-current-buffer buffer (buffer-string)))))
(defun org-git-blob-sha (gitdir object)
"Return sha of the referenced object"
diff --git a/contrib/lisp/org-interactive-query.el b/contrib/lisp/org-interactive-query.el
index ab6669b..57665e2 100644
--- a/contrib/lisp/org-interactive-query.el
+++ b/contrib/lisp/org-interactive-query.el
@@ -1,6 +1,6 @@
;;; org-interactive-query.el --- Interactive modification of agenda query
;;
-;; Copyright 2007-2012 Free Software Foundation, Inc.
+;; Copyright 2007-2013 Free Software Foundation, Inc.
;;
;; Author: Christopher League <league at contrapunctus dot net>
;; Version: 1.0
@@ -19,8 +19,7 @@
;; 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, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
diff --git a/contrib/lisp/org-invoice.el b/contrib/lisp/org-invoice.el
index c951d4e..88ff48f 100644
--- a/contrib/lisp/org-invoice.el
+++ b/contrib/lisp/org-invoice.el
@@ -1,6 +1,6 @@
;;; org-invoice.el --- Help manage client invoices in OrgMode
;;
-;; Copyright (C) 2008-2012 pmade inc. (Peter Jones pjones@pmade.com)
+;; Copyright (C) 2008-2013 pmade inc. (Peter Jones pjones@pmade.com)
;;
;; This file is not part of GNU Emacs.
;;
@@ -23,7 +23,7 @@
;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
;;
-;; Commentary:
+;;; Commentary:
;;
;; Building on top of the terrific OrgMode, org-invoice tries to
;; provide functionality for managing invoices. Currently, it does
@@ -226,8 +226,8 @@ looks like tree2, where the level is 2."
(setq
org-invoice-total-time (+ org-invoice-total-time work)
org-invoice-total-price (+ org-invoice-total-price price)))
- (setq total (and total (org-minutes-to-hh:mm-string total)))
- (setq work (and work (org-minutes-to-hh:mm-string work)))
+ (setq total (and total (org-minutes-to-clocksum-string total)))
+ (setq work (and work (org-minutes-to-clocksum-string work)))
(insert-before-markers
(concat "|" title
(cond
@@ -251,7 +251,7 @@ looks like tree2, where the level is 2."
(when with-summary
(insert-before-markers
(concat "|-\n|Total:|"
- (org-minutes-to-hh:mm-string org-invoice-total-time)
+ (org-minutes-to-clocksum-string org-invoice-total-time)
(and with-price (concat "|" (format "%.2f" org-invoice-total-price)))
"|\n")))))
@@ -290,7 +290,7 @@ information about dblock parameters, please see the Org manual):
:summary Set to nil to turn off the final summary line."
(let ((scope (plist-get params :scope))
(org-invoice-table-params params)
- (zone (move-marker (make-marker) (point)))
+ (zone (point-marker))
table)
(unless scope (setq scope 'default))
(unless (plist-member params :price) (plist-put params :price t))
diff --git a/contrib/lisp/org-jira.el b/contrib/lisp/org-jira.el
index 2037029..57128fb 100644
--- a/contrib/lisp/org-jira.el
+++ b/contrib/lisp/org-jira.el
@@ -1,6 +1,6 @@
;;; org-jira.el --- add a jira:ticket protocol to Org
(defconst org-jira-version "0.1")
-;; Copyright (C) 2008-2012 Jonathan Arkell.
+;; Copyright (C) 2008-2013 Jonathan Arkell.
;; Author: Jonathan Arkell <jonnay@jonnay.net>
;; This file is not part of GNU Emacs.
@@ -14,9 +14,8 @@
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
-;; For a copy of the GNU General Public License, search the Internet,
-;; or write to the Free Software Foundation, Inc., 59 Temple Place,
-;; Suite 330, Boston, MA 02111-1307 USA
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This adds a jira protocol to org mode.
diff --git a/contrib/lisp/org-learn.el b/contrib/lisp/org-learn.el
index 0d5752b..1f5e76c 100644
--- a/contrib/lisp/org-learn.el
+++ b/contrib/lisp/org-learn.el
@@ -1,6 +1,6 @@
;;; org-learn.el --- Implements SuperMemo's incremental learning algorithm
-;; Copyright (C) 2009-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2009-2013 Free Software Foundation, Inc.
;; Author: John Wiegley <johnw at gnu dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -9,12 +9,12 @@
;;
;; This file is not part of GNU Emacs.
;;
-;; GNU Emacs is free software: you can redistribute it and/or modify
+;; 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.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
diff --git a/contrib/lisp/org-mac-iCal.el b/contrib/lisp/org-mac-iCal.el
index 0fdc95f..afec84b 100644
--- a/contrib/lisp/org-mac-iCal.el
+++ b/contrib/lisp/org-mac-iCal.el
@@ -1,26 +1,25 @@
;;; org-mac-iCal.el --- Imports events from iCal.app to the Emacs diary
-;; Copyright (C) 2009-2012 Christopher Suckling
+;; Copyright (C) 2009-2013 Christopher Suckling
;; Author: Christopher Suckling <suckling at gmail dot com>
+;; Version: 0.1057.104
+;; Keywords: outlines, calendar
+
+;; This file is not part of GNU Emacs.
-;; This file is Free Software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; It 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.
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
-
-;; Version: 0.1057.104
-;; Keywords: outlines, calendar
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
@@ -99,7 +98,7 @@ the the Emacs diary"
;; for each calendar, concatenate individual events into a single ics file
(with-temp-buffer
(shell-command "sw_vers" (current-buffer))
- (when (re-search-backward "10\\.[567]" nil t)
+ (when (re-search-backward "10\\.[5678]" nil t)
(omi-concat-leopard-ics all-calendars)))
;; move all caldav ics files to the same place as local ics files
diff --git a/contrib/lisp/org-mac-link-grabber.el b/contrib/lisp/org-mac-link-grabber.el
index b422bfb..0598617 100644
--- a/contrib/lisp/org-mac-link-grabber.el
+++ b/contrib/lisp/org-mac-link-grabber.el
@@ -1,7 +1,7 @@
;;; org-mac-link-grabber.el --- Grab links and url from various mac
-;;; application and insert them as links into org-mode documents
+;; Application and insert them as links into org-mode documents
;;
-;; Copyright (c) 2010-2012 Free Software Foundation, Inc.
+;; Copyright (c) 2010-2013 Free Software Foundation, Inc.
;;
;; Author: Anthony Lander <anthony.lander@gmail.com>
;; Version: 1.0.1
@@ -20,8 +20,7 @@
;; 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, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;
diff --git a/contrib/lisp/org-mac-message.el b/contrib/lisp/org-mac-message.el
new file mode 100644
index 0000000..dca63c9
--- /dev/null
+++ b/contrib/lisp/org-mac-message.el
@@ -0,0 +1,217 @@
+;;; org-mac-message.el --- Links to Apple Mail.app messages from within Org-mode
+
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
+
+;; Authors: John Wiegley <johnw@gnu.org>
+;; Christopher Suckling <suckling at gmail dot com>
+
+;; Keywords: outlines, hypermedia, calendar, wp
+
+;; This file is not part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;; This file implements links to Apple Mail.app messages from within
+;; Org-mode. Org-mode does not load this module by default - if you
+;; would actually like this to happen then configure the variable
+;; `org-modules' and add Org's contrib/ directory to your `load-path'.
+
+;; If you would like to create links to all flagged messages in an
+;; Apple Mail.app account, please customize the variable
+;; `org-mac-mail-account' and then call one of the following functions:
+
+;; (org-mac-message-insert-selected) copies a formatted list of links to
+;; the kill ring.
+
+;; (org-mac-message-insert-selected) inserts at point links to any
+;; messages selected in Mail.app.
+
+;; (org-mac-message-insert-flagged) searches within an org-mode buffer
+;; for a specific heading, creating it if it doesn't exist. Any
+;; message:// links within the first level of the heading are deleted
+;; and replaced with links to flagged messages.
+
+;;; Code:
+
+(require 'org)
+
+(defgroup org-mac-flagged-mail nil
+ "Options concerning linking to flagged Mail.app messages."
+ :tag "Org Mail.app"
+ :group 'org-link)
+
+(defcustom org-mac-mail-account "customize"
+ "The Mail.app account in which to search for flagged messages."
+ :group 'org-mac-flagged-mail
+ :type 'string)
+
+(org-add-link-type "message" 'org-mac-message-open)
+
+;; In mac.c, removed in Emacs 23.
+(declare-function do-applescript "org-mac-message" (script))
+(unless (fboundp 'do-applescript)
+ ;; Need to fake this using shell-command-to-string
+ (defun do-applescript (script)
+ (let (start cmd return)
+ (while (string-match "\n" script)
+ (setq script (replace-match "\r" t t script)))
+ (while (string-match "'" script start)
+ (setq start (+ 2 (match-beginning 0))
+ script (replace-match "\\'" t t script)))
+ (setq cmd (concat "osascript -e '" script "'"))
+ (setq return (shell-command-to-string cmd))
+ (concat "\"" (org-trim return) "\""))))
+
+(defun org-mac-message-open (message-id)
+ "Visit the message with the given MESSAGE-ID.
+This will use the command `open' with the message URL."
+ (start-process (concat "open message:" message-id) nil
+ "open" (concat "message://<" (substring message-id 2) ">")))
+
+(defun as-get-selected-mail ()
+ "AppleScript to create links to selected messages in Mail.app."
+ (do-applescript
+ (concat
+ "tell application \"Mail\"\n"
+ "set theLinkList to {}\n"
+ "set theSelection to selection\n"
+ "repeat with theMessage in theSelection\n"
+ "set theID to message id of theMessage\n"
+ "set theSubject to subject of theMessage\n"
+ "set theLink to \"message://\" & theID & \"::split::\" & theSubject & \"\n\"\n"
+ "copy theLink to end of theLinkList\n"
+ "end repeat\n"
+ "return theLinkList as string\n"
+ "end tell")))
+
+(defun as-get-flagged-mail ()
+ "AppleScript to create links to flagged messages in Mail.app."
+ (do-applescript
+ (concat
+ ;; Is Growl installed?
+ "tell application \"System Events\"\n"
+ "set growlHelpers to the name of every process whose creator type contains \"GRRR\"\n"
+ "if (count of growlHelpers) > 0 then\n"
+ "set growlHelperApp to item 1 of growlHelpers\n"
+ "else\n"
+ "set growlHelperApp to \"\"\n"
+ "end if\n"
+ "end tell\n"
+
+ ;; Get links
+ "tell application \"Mail\"\n"
+ "set theMailboxes to every mailbox of account \"" org-mac-mail-account "\"\n"
+ "set theLinkList to {}\n"
+ "repeat with aMailbox in theMailboxes\n"
+ "set theSelection to (every message in aMailbox whose flagged status = true)\n"
+ "repeat with theMessage in theSelection\n"
+ "set theID to message id of theMessage\n"
+ "set theSubject to subject of theMessage\n"
+ "set theLink to \"message://\" & theID & \"::split::\" & theSubject & \"\n\"\n"
+ "copy theLink to end of theLinkList\n"
+
+ ;; Report progress through Growl
+ ;; This "double tell" idiom is described in detail at
+ ;; http://macscripter.net/viewtopic.php?id=24570 The
+ ;; script compiler needs static knowledge of the
+ ;; growlHelperApp. Hmm, since we're compiling
+ ;; on-the-fly here, this is likely to be way less
+ ;; portable than I'd hoped. It'll work when the name
+ ;; is still "GrowlHelperApp", though.
+ "if growlHelperApp is not \"\" then\n"
+ "tell application \"GrowlHelperApp\"\n"
+ "tell application growlHelperApp\n"
+ "set the allNotificationsList to {\"FlaggedMail\"}\n"
+ "set the enabledNotificationsList to allNotificationsList\n"
+ "register as application \"FlaggedMail\" all notifications allNotificationsList default notifications enabledNotificationsList icon of application \"Mail\"\n"
+ "notify with name \"FlaggedMail\" title \"Importing flagged message\" description theSubject application name \"FlaggedMail\"\n"
+ "end tell\n"
+ "end tell\n"
+ "end if\n"
+ "end repeat\n"
+ "end repeat\n"
+ "return theLinkList as string\n"
+ "end tell")))
+
+(defun org-mac-message-get-links (&optional select-or-flag)
+ "Create links to the messages currently selected or flagged in Mail.app.
+This will use AppleScript to get the message-id and the subject of the
+messages in Mail.app and make a link out of it.
+When SELECT-OR-FLAG is \"s\", get the selected messages (this is also
+the default). When SELECT-OR-FLAG is \"f\", get the flagged messages.
+The Org-syntax text will be pushed to the kill ring, and also returned."
+ (interactive "sLink to (s)elected or (f)lagged messages: ")
+ (setq select-or-flag (or select-or-flag "s"))
+ (message "AppleScript: searching mailboxes...")
+ (let* ((as-link-list
+ (if (string= select-or-flag "s")
+ (as-get-selected-mail)
+ (if (string= select-or-flag "f")
+ (as-get-flagged-mail)
+ (error "Please select \"s\" or \"f\""))))
+ (link-list
+ (mapcar
+ (lambda (x) (if (string-match "\\`\"\\(.*\\)\"\\'" x) (setq x (match-string 1 x))) x)
+ (split-string as-link-list "[\r\n]+")))
+ split-link URL description orglink orglink-insert rtn orglink-list)
+ (while link-list
+ (setq split-link (split-string (pop link-list) "::split::"))
+ (setq URL (car split-link))
+ (setq description (cadr split-link))
+ (when (not (string= URL ""))
+ (setq orglink (org-make-link-string URL description))
+ (push orglink orglink-list)))
+ (setq rtn (mapconcat 'identity orglink-list "\n"))
+ (kill-new rtn)
+ rtn))
+
+(defun org-mac-message-insert-selected ()
+ "Insert a link to the messages currently selected in Mail.app.
+This will use AppleScript to get the message-id and the subject of the
+active mail in Mail.app and make a link out of it."
+ (interactive)
+ (insert (org-mac-message-get-links "s")))
+
+;; The following line is for backward compatibility
+(defalias 'org-mac-message-insert-link 'org-mac-message-insert-selected)
+
+(defun org-mac-message-insert-flagged (org-buffer org-heading)
+ "Asks for an org buffer and a heading within it, and replace message links.
+If heading exists, delete all message:// links within heading's first
+level. If heading doesn't exist, create it at point-max. Insert
+list of message:// links to flagged mail after heading."
+ (interactive "bBuffer in which to insert links: \nsHeading after which to insert links: ")
+ (with-current-buffer org-buffer
+ (goto-char (point-min))
+ (let ((isearch-forward t)
+ (message-re "\\[\\[\\(message:\\)\\([^]]+\\)\\]\\(\\[\\([^]]+\\)\\]\\)?\\]"))
+ (if (org-goto-local-search-headings org-heading nil t)
+ (if (not (eobp))
+ (progn
+ (save-excursion
+ (while (re-search-forward
+ message-re (save-excursion (outline-next-heading)) t)
+ (delete-region (match-beginning 0) (match-end 0)))
+ (insert "\n" (org-mac-message-get-links "f")))
+ (flush-lines "^$" (point) (outline-next-heading)))
+ (insert "\n" (org-mac-message-get-links "f")))
+ (goto-char (point-max))
+ (insert "\n")
+ (org-insert-heading nil t)
+ (insert org-heading "\n" (org-mac-message-get-links "f"))))))
+
+(provide 'org-mac-message)
+
+;;; org-mac-message.el ends here
diff --git a/contrib/lisp/org-mairix.el b/contrib/lisp/org-mairix.el
index 367a866..b08897d 100644
--- a/contrib/lisp/org-mairix.el
+++ b/contrib/lisp/org-mairix.el
@@ -1,8 +1,10 @@
;;; org-mairix.el - Support for hooking mairix search into Org for different MUAs
;;
-;; Copyright (C) 2007-2012 Georg C. F. Greve
+;; Copyright (C) 2007-2013 Georg C. F. Greve
;; mutt support by Adam Spiers <orgmode at adamspiers dot org>
;;
+;; This file is not part of GNU Emacs.
+;;
;; Author: Georg C. F. Greve <greve at fsfeurope dot org>
;; Keywords: outlines, hypermedia, calendar, wp, email, mairix
;; Purpose: Integrate mairix email searching into Org mode
@@ -20,9 +22,7 @@
;; License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; USAGE NOTE
;;
diff --git a/contrib/lisp/org-man.el b/contrib/lisp/org-man.el
index 27e8cca..a9db83d 100644
--- a/contrib/lisp/org-man.el
+++ b/contrib/lisp/org-man.el
@@ -7,27 +7,25 @@
;;
;; This file is not yet part of GNU Emacs.
;;
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
(require 'org)
-(org-add-link-type "man" 'org-man-open)
+(org-add-link-type "man" 'org-man-open 'org-man-export)
(add-hook 'org-store-link-functions 'org-man-store-link)
(defcustom org-man-command 'man
@@ -59,6 +57,17 @@ PATH should be a topic that can be thrown at the man command."
(match-string 1 (buffer-name))
(error "Cannot create link to this man page")))
+(defun org-man-export (link description format)
+ "Export a man page link from Org files."
+ (let ((path (format "http://man.he.net/?topic=%s&section=all" link))
+ (desc (or description link)))
+ (cond
+ ((eq format 'html) (format "<a target=\"_blank\" href=\"%s\">%s</a>" path desc))
+ ((eq format 'latex) (format "\\href{%s}{%s}" path desc))
+ ((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
+ ((eq format 'ascii) (format "%s (%s)" desc path))
+ (t path))))
+
(provide 'org-man)
;;; org-man.el ends here
diff --git a/contrib/lisp/org-md.el b/contrib/lisp/org-md.el
deleted file mode 100644
index 4579ca3..0000000
--- a/contrib/lisp/org-md.el
+++ /dev/null
@@ -1,461 +0,0 @@
-;;; org-md.el --- Markdown Back-End for Org Export Engine
-
-;; Copyright (C) 2012 Free Software Foundation, Inc.
-
-;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
-;; Keywords: org, wp, tex
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This library implements a Markdown back-end (vanilla flavour) for
-;; Org exporter, based on `e-html'.
-;;
-;; It provides two commands for export, depending on the desired
-;; output: `org-md-export-as-markdown' (temporary buffer) and
-;; `org-md-export-to-markdown' ("md" file).
-
-;;; Code:
-
-(require 'org-e-html)
-
-
-
-;;; User-Configurable Variables
-
-(defgroup org-export-md nil
- "Options specific to Markdown export back-end."
- :tag "Org Markdown"
- :group 'org-export
- :version "24.2")
-
-(defcustom org-md-headline-style 'atx
- "Style used to format headlines.
-This variable can be set to either `atx' or `setext'."
- :group 'org-export-md
- :type '(choice
- (const :tag "Use \"atx\" style" atx)
- (const :tag "Use \"Setext\" style" setext)))
-
-
-
-;;; Define Back-End
-
-(org-export-define-derived-backend md e-html
- :export-block ("MD" "MARKDOWN")
- :filters-alist ((:filter-parse-tree . org-md-separate-elements))
- :translate-alist ((bold . org-md-bold)
- (code . org-md-verbatim)
- (example-block . org-md-example-block)
- (footnote-definition . ignore)
- (footnote-reference . ignore)
- (headline . org-md-headline)
- (horizontal-rule . org-md-horizontal-rule)
- (inline-src-block . org-md-verbatim)
- (italic . org-md-italic)
- (item . org-md-item)
- (line-break . org-md-line-break)
- (link . org-md-link)
- (paragraph . org-md-paragraph)
- (plain-list . org-md-plain-list)
- (plain-text . org-md-plain-text)
- (quote-block . org-md-quote-block)
- (quote-section . org-md-example-block)
- (section . org-md-section)
- (src-block . org-md-example-block)
- (template . org-md-template)
- (verbatim . org-md-verbatim)))
-
-
-
-;;; Filters
-
-(defun org-md-separate-elements (tree backend info)
- "Make sure elements are separated by at least one blank line.
-
-TREE is the parse tree being exported. BACKEND is the export
-back-end used. INFO is a plist used as a communication channel.
-
-Assume BACKEND is `md'."
- (org-element-map
- tree org-element-all-elements
- (lambda (elem)
- (unless (eq (org-element-type elem) 'org-data)
- (org-element-put-property
- elem :post-blank
- (let ((post-blank (org-element-property :post-blank elem)))
- (if (not post-blank) 1 (max 1 post-blank)))))))
- ;; Return updated tree.
- tree)
-
-
-
-;;; Transcode Functions
-
-;;;; Bold
-
-(defun org-md-bold (bold contents info)
- "Transcode BOLD object into Markdown format.
-CONTENTS is the text within bold markup. INFO is a plist used as
-a communication channel."
- (format "**%s**" contents))
-
-
-;;;; Code and Verbatim
-
-(defun org-md-verbatim (verbatim contents info)
- "Transcode VERBATIM object into Markdown format.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (let ((value (org-element-property :value verbatim)))
- (format (cond ((not (string-match "`" value)) "`%s`")
- ((or (string-match "\\``" value)
- (string-match "`\\'" value))
- "`` %s ``")
- (t "``%s``"))
- value)))
-
-
-;;;; Example Block and Src Block
-
-(defun org-md-example-block (example-block contents info)
- "Transcode EXAMPLE-BLOCK element into Markdown format.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- (replace-regexp-in-string
- "^" " "
- (org-remove-indentation
- (org-element-property :value example-block))))
-
-
-;;;; Headline
-
-(defun org-md-headline (headline contents info)
- "Transcode HEADLINE element into Markdown format.
-CONTENTS is the headline contents. INFO is a plist used as
-a communication channel."
- (unless (org-element-property :footnote-section-p headline)
- (let* ((level (org-export-get-relative-level headline info))
- (title (org-export-data (org-element-property :title headline) info))
- (todo (and (plist-get info :with-todo-keywords)
- (let ((todo (org-element-property :todo-keyword
- headline)))
- (and todo (concat (org-export-data todo info) " ")))))
- (tags (and (plist-get info :with-tags)
- (let ((tag-list (org-export-get-tags headline info)))
- (and tag-list
- (format " :%s:"
- (mapconcat 'identity tag-list ":"))))))
- (priority
- (and (plist-get info :with-priority)
- (let ((char (org-element-property :priority headline)))
- (and char (format "[#%c] " char)))))
- ;; Headline text without tags.
- (heading (concat todo priority title)))
- (cond
- ;; Cannot create an headline. Fall-back to a list.
- ((or (org-export-low-level-p headline info)
- (not (memq org-md-headline-style '(atx setext)))
- (and (eq org-md-headline-style 'atx) (> level 6))
- (and (eq org-md-headline-style 'setext) (> level 2)))
- (let ((bullet
- (if (not (org-export-numbered-headline-p headline info)) "-"
- (concat (number-to-string
- (car (last (org-export-get-headline-number
- headline info))))
- "."))))
- (concat bullet (make-string (- 4 (length bullet)) ? ) heading tags
- "\n\n"
- (and contents
- (replace-regexp-in-string "^" " " contents)))))
- ;; Use "Setext" style.
- ((eq org-md-headline-style 'setext)
- (concat heading tags "\n"
- (make-string (length heading) (if (= level 1) ?= ?-))
- "\n\n"
- contents))
- ;; Use "atx" style.
- (t (concat (make-string level ?#) " " heading tags "\n\n" contents))))))
-
-
-;;;; Horizontal Rule
-
-(defun org-md-horizontal-rule (horizontal-rule contents info)
- "Transcode HORIZONTAL-RULE element into Markdown format.
-CONTENTS is the horizontal rule contents. INFO is a plist used
-as a communication channel."
- "---")
-
-
-;;;; Italic
-
-(defun org-md-italic (italic contents info)
- "Transcode ITALIC object into Markdown format.
-CONTENTS is the text within italic markup. INFO is a plist used
-as a communication channel."
- (format "*%s*" contents))
-
-
-;;;; Item
-
-(defun org-md-item (item contents info)
- "Transcode ITEM element into Markdown format.
-CONTENTS is the item contents. INFO is a plist used as
-a communication channel."
- (let* ((type (org-element-property :type (org-export-get-parent item)))
- (struct (org-element-property :structure item))
- (bullet (if (not (eq type 'ordered)) "-"
- (concat (number-to-string
- (car (last (org-list-get-item-number
- (org-element-property :begin item)
- struct
- (org-list-prevs-alist struct)
- (org-list-parents-alist struct)))))
- "."))))
- (concat bullet
- (make-string (- 4 (length bullet)) ? )
- (case (org-element-property :checkbox item)
- (on "[X] ")
- (trans "[-] ")
- (off "[ ] "))
- (let ((tag (org-element-property :tag item)))
- (and tag (format "**%s:** "(org-export-data tag info))))
- (org-trim (replace-regexp-in-string "^" " " contents)))))
-
-
-;;;; Line Break
-
-(defun org-md-line-break (line-break contents info)
- "Transcode LINE-BREAK object into Markdown format.
-CONTENTS is nil. INFO is a plist used as a communication
-channel."
- " ")
-
-
-;;;; Link
-
-(defun org-md-link (link contents info)
- "Transcode LINE-BREAK object into Markdown format.
-CONTENTS is the link's description. INFO is a plist used as
-a communication channel."
- (let ((--link-org-files-as-html-maybe
- (function
- (lambda (raw-path info)
- ;; Treat links to `file.org' as links to `file.html', if
- ;; needed. See `org-e-html-link-org-files-as-html'.
- (cond
- ((and org-e-html-link-org-files-as-html
- (string= ".org"
- (downcase (file-name-extension raw-path "."))))
- (concat (file-name-sans-extension raw-path) "."
- (plist-get info :html-extension)))
- (t raw-path)))))
- (type (org-element-property :type link)))
- (cond ((member type '("custom-id" "id"))
- (let ((destination (org-export-resolve-id-link link info)))
- (if (stringp destination) ; External file.
- (let ((path (funcall --link-org-files-as-html-maybe
- destination info)))
- (if (not contents) (format "<%s>" path)
- (format "[%s](%s)" contents path)))
- (concat
- (and contents (concat contents " "))
- (format "(%s)"
- (format (org-export-translate "See section %s" :html info)
- (mapconcat 'number-to-string
- (org-export-get-headline-number
- destination info)
- ".")))))))
- ((org-export-inline-image-p link org-e-html-inline-image-rules)
- (format "![%s](%s)"
- (let ((caption
- (org-element-property
- :caption (org-export-get-parent-element link))))
- (when caption (org-export-data (car caption) info)))
- path))
- ((string= type "coderef")
- (let ((ref (org-element-property :path link)))
- (format (org-export-get-coderef-format ref contents)
- (org-export-resolve-coderef ref info))))
- ((equal type "radio")
- (let ((destination (org-export-resolve-radio-link link info)))
- (org-export-data (org-element-contents destination) info)))
- ((equal type "fuzzy")
- (let ((destination (org-export-resolve-fuzzy-link link info)))
- ;; Ignore invisible "#+TARGET: path".
- (unless (eq (org-element-type destination) 'keyword)
- (if (org-string-nw-p contents) contents
- (when destination
- (let ((number (org-export-get-ordinal destination info)))
- (when number
- (if (atom number) (number-to-string number)
- (mapconcat 'number-to-string number ".")))))))))
- (t (let* ((raw-path (org-element-property :path link))
- (path (cond
- ((member type '("http" "https" "ftp"))
- (concat type ":" raw-path))
- ((equal type "file")
- ;; Extract just the file path and strip
- ;; all other components.
- (when (string-match "\\(.+\\)::.+" raw-path)
- (setq raw-path (match-string 1 raw-path)))
- ;; Treat links to ".org" files as ".html",
- ;; if needed.
- (setq raw-path
- (funcall --link-org-files-as-html-maybe
- raw-path info))
- ;; If file path is absolute, prepend it
- ;; with protocol component - "file://".
- (if (not (file-name-absolute-p raw-path)) raw-path
- (concat "file://" (expand-file-name raw-path))))
- (t raw-path))))
- (if (not contents) (format "<%s>" path)
- (format "[%s](%s)" contents path)))))))
-
-
-;;;; Paragraph
-
-(defun org-md-paragraph (paragraph contents info)
- "Transcode PARAGRAPH element into Markdown format.
-CONTENTS is the paragraph contents. INFO is a plist used as
-a communication channel."
- (let ((first-object (car (org-element-contents paragraph))))
- ;; If paragraph starts with a #, protect it.
- (if (and (stringp first-object) (string-match "\\`#" first-object))
- (replace-regexp-in-string "\\`#" "\\#" contents nil t)
- contents)))
-
-
-;;;; Plain List
-
-(defun org-md-plain-list (plain-list contents info)
- "Transcode PLAIN-LIST element into Markdown format.
-CONTENTS is the plain-list contents. INFO is a plist used as
-a communication channel."
- contents)
-
-
-;;;; Plain Text
-
-(defun org-md-plain-text (text info)
- "Transcode a TEXT string into Markdown format.
-TEXT is the string to transcode. INFO is a plist holding
-contextual information."
- ;; Protect ambiguous #. This will protect # at the beginning of
- ;; a line, but not at the beginning of a paragraph. See
- ;; `org-md-paragraph'.
- (setq text (replace-regexp-in-string "\n#" "\n\\\\#" text))
- ;; Protect ambiguous !
- (setq text (replace-regexp-in-string "\\(!\\)\\[" "\\\\!" text nil nil 1))
- ;; Protect `, *, _ and \
- (setq text
- (replace-regexp-in-string
- "[`*_\\]" (lambda (rep) (concat "\\\\" (match-string 1 rep))) text))
- ;; Handle special strings, if required.
- (when (plist-get info :with-special-strings)
- (setq text (org-e-html-convert-special-strings text)))
- ;; Handle break preservation, if required.
- (when (plist-get info :preserve-breaks)
- (setq text (replace-regexp-in-string "[ \t]*\n" " \n" text)))
- ;; Return value.
- text)
-
-
-;;;; Quote Block
-
-(defun org-md-quote-block (quote-block contents info)
- "Transcode QUOTE-BLOCK element into Markdown format.
-CONTENTS is the quote-block contents. INFO is a plist used as
-a communication channel."
- (replace-regexp-in-string
- "^" "> "
- (replace-regexp-in-string "\n\\'" "" contents)))
-
-
-;;;; Section
-
-(defun org-md-section (section contents info)
- "Transcode SECTION element into Markdown format.
-CONTENTS is the section contents. INFO is a plist used as
-a communication channel."
- contents)
-
-
-;;;; Template
-
-(defun org-md-template (contents info)
- "Return complete document string after Markdown conversion.
-CONTENTS is the transcoded contents string. INFO is a plist used
-as a communication channel."
- contents)
-
-
-
-;;; Interactive function
-
-;;;###autoload
-(defun org-md-export-as-markdown (&optional subtreep visible-only)
- "Export current buffer to a text buffer.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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.
-
-Export is done in a buffer named \"*Org MD Export*\", which will
-be displayed when `org-export-show-temporary-export-buffer' is
-non-nil."
- (interactive)
- (let ((outbuf (org-export-to-buffer
- 'md "*Org MD Export*" subtreep visible-only)))
- (with-current-buffer outbuf (text-mode))
- (when org-export-show-temporary-export-buffer
- (switch-to-buffer-other-window outbuf))))
-
-
-;;;###autoload
-(defun org-md-export-to-markdown (&optional subtreep visible-only pub-dir)
- "Export current buffer to a Markdown file.
-
-If narrowing is active in the current buffer, only export its
-narrowed part.
-
-If a region is active, export that region.
-
-When optional argument SUBTREEP is non-nil, export 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 PUB-DIR is set, use it as the publishing
-directory.
-
-Return output file's name."
- (interactive)
- (let ((outfile (org-export-output-file-name ".md" subtreep pub-dir)))
- (org-export-to-file 'md outfile subtreep visible-only)))
-
-
-(provide 'org-md)
-;;; org-md.el ends here
diff --git a/contrib/lisp/org-mew.el b/contrib/lisp/org-mew.el
new file mode 100644
index 0000000..ca6a352
--- /dev/null
+++ b/contrib/lisp/org-mew.el
@@ -0,0 +1,364 @@
+;;; org-mew.el --- Support for links to Mew messages from within Org-mode
+
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
+
+;; Author: Tokuya Kameshima <kames at fa2 dot so-net dot ne dot jp>
+;; Keywords: outlines, hypermedia, calendar, wp
+;; Homepage: http://orgmode.org
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+
+;; This file implements links to Mew messages from within Org-mode.
+;; Org-mode loads this module by default - if this is not what you want,
+;; configure the variable `org-modules'.
+;;
+;; Here is an example of workflow:
+
+;; In your ~/.mew.el configuration file:
+;;
+;; (define-key mew-summary-mode-map "'" 'org-mew-search)
+;; (eval-after-load "mew-summary"
+;; '(define-key mew-summary-mode-map "\C-o" 'org-mew-capture))
+
+;; 1. In the Mew's inbox folder, take a glance at new messages to find
+;; a message that requires any action.
+
+;; 2. If the message is a reply from somebody and associated with the
+;; existing orgmode entry, type M-x `org-mew-search' RET (or press
+;; the ' key simply) to find the entry. If you can find the entry
+;; successfully and think you should start the task right now,
+;; start the task by M-x `org-agenda-clock-in' RET.
+
+;; 3. If the message is a new message, type M-x `org-mew-capture' RET,
+;; enter the refile folder, and the buffer to capture the message
+;; is shown up (without selecting the template by hand). Then you
+;; can fill the template and type C-c C-c to complete the capture.
+;; Note that you can configure `org-capture-templates' so that the
+;; captured entry has a link to the message.
+
+;;; Code:
+
+(require 'org)
+
+(defgroup org-mew nil
+ "Options concerning the Mew link."
+ :tag "Org Startup"
+ :group 'org-link)
+
+(defcustom org-mew-link-to-refile-destination t
+ "Create a link to the refile destination if the message is marked as refile."
+ :group 'org-mew
+ :type 'boolean)
+
+(defcustom org-mew-inbox-folder nil
+ "The folder where new messages are incorporated.
+If `org-mew-inbox-folder' is non-nil, `org-mew-open' locates the message
+in this inbox folder as well as the folder specified by the link."
+ :group 'org-mew
+ :type 'string)
+
+(defcustom org-mew-use-id-db t
+ "Use ID database to locate the message if id.db is created."
+ :group 'org-mew
+ :type 'boolean)
+
+(defcustom org-mew-subject-alist
+ (list (cons (concat "^\\(?:\\(?:re\\|fwd?\\): *\\)*"
+ "\\(?:[[(][a-z0-9._-]+[:,]? [0-9]+[])]\\)? *"
+ "\\(?:\\(?:re\\|fwd?\\): *\\)*"
+ "\\(.*\\)[ \t]*")
+ 1))
+ "Alist of subject regular expression and matched group number for search."
+ :group 'org-mew
+ :type '(repeat (cons (regexp) (integer))))
+
+(defcustom org-mew-capture-inbox-folders nil
+ "List of inbox folders whose messages need refile marked before capture.
+`org-mew-capture' will ask you to put the refile mark on the
+message if the message's folder is any of these folders and the
+message is not marked. Nil means `org-mew-capture' never ask you
+destination folders before capture."
+ :group 'org-mew
+ :type '(repeat string))
+
+(defcustom org-mew-capture-guess-alist nil
+ "Alist of the regular expression of the folder name and the capture
+template selection keys.
+
+For example,
+ '((\"^%emacs-orgmode$\" . \"o\")
+ (\"\" . \"t\"))
+the messages in \"%emacs-orgmode\" folder will be captured with
+the capture template associated with \"o\" key, and any other
+messages will be captured with the capture template associated
+with \"t\" key."
+ :group 'org-mew
+ :type '(repeat (cons regexp string)))
+
+;; Declare external functions and variables
+(declare-function mew-cache-hit "ext:mew-cache" (fld msg &optional must-hit))
+(declare-function mew-case-folder "ext:mew-func" (case folder))
+(declare-function mew-folder-path-to-folder
+ "ext:mew-func" (path &optional has-proto))
+(declare-function mew-idstr-to-id-list "ext:mew-header" (idstr &optional rev))
+(declare-function mew-folder-remotep "ext:mew-func" (folder))
+(declare-function mew-folder-virtualp "ext:mew-func" (folder))
+(declare-function mew-header-get-value "ext:mew-header"
+ (field &optional as-list))
+(declare-function mew-init "ext:mew" ())
+(declare-function mew-refile-get "ext:mew-refile" (msg))
+(declare-function mew-sinfo-get-case "ext:mew-summary" ())
+(declare-function mew-summary-diag-global "ext:mew-thread" (id opt who))
+(declare-function mew-summary-display "ext:mew-summary2" (&optional redisplay))
+(declare-function mew-summary-folder-name "ext:mew-syntax" (&optional ext))
+(declare-function mew-summary-get-mark "ext:mew-mark" ())
+(declare-function mew-summary-message-number2 "ext:mew-syntax" ())
+(declare-function mew-summary-pick-with-mewl "ext:mew-pick"
+ (pattern folder src-msgs))
+(declare-function mew-summary-refile "ext:mew-refile" (&optional report))
+(declare-function mew-summary-search-msg "ext:mew-const" (msg))
+(declare-function mew-summary-set-message-buffer "ext:mew-summary3" (fld msg))
+(declare-function mew-summary-visit-folder "ext:mew-summary4"
+ (folder &optional goend no-ls))
+(declare-function mew-window-push "ext:mew" ())
+(declare-function mew-expand-folder "ext:mew-func" (folder))
+(declare-function mew-case:folder-folder "ext:mew-func" (case:folder))
+(declare-function mew "ext:mew" (&optional arg))
+(declare-function mew-message-goto-summary "ext:mew-message" ())
+(declare-function mew-summary-mode "ext:mew-summary" ())
+
+(defvar mew-init-p)
+(defvar mew-mark-afterstep-spec)
+(defvar mew-summary-goto-line-then-display)
+
+;; Install the link type
+(org-add-link-type "mew" 'org-mew-open)
+(add-hook 'org-store-link-functions 'org-mew-store-link)
+
+;; Implementation
+(defun org-mew-store-link ()
+ "Store a link to a Mew folder or message."
+ (save-window-excursion
+ (if (eq major-mode 'mew-message-mode)
+ (mew-message-goto-summary))
+ (when (memq major-mode '(mew-summary-mode mew-virtual-mode))
+ (let ((msgnum (mew-summary-message-number2))
+ (folder-name (org-mew-folder-name)))
+ (if (fboundp 'mew-summary-set-message-buffer)
+ (mew-summary-set-message-buffer folder-name msgnum)
+ (set-buffer (mew-cache-hit folder-name msgnum t)))
+ (let* ((message-id (mew-header-get-value "Message-Id:"))
+ (from (mew-header-get-value "From:"))
+ (to (mew-header-get-value "To:"))
+ (date (mew-header-get-value "Date:"))
+ (date-ts (and date (format-time-string
+ (org-time-stamp-format t)
+ (date-to-time date))))
+ (date-ts-ia (and date (format-time-string
+ (org-time-stamp-format t t)
+ (date-to-time date))))
+ (subject (mew-header-get-value "Subject:"))
+ desc link)
+ (org-store-link-props :type "mew" :from from :to to
+ :subject subject :message-id message-id)
+ (when date
+ (org-add-link-props :date date :date-timestamp date-ts
+ :date-timestamp-inactive date-ts-ia))
+ (setq message-id (org-remove-angle-brackets message-id))
+ (setq desc (org-email-link-description))
+ (setq link (concat "mew:" folder-name "#" message-id))
+ (org-add-link-props :link link :description desc)
+ link)))))
+
+(defun org-mew-folder-name ()
+ "Return the folder name of the current message."
+ (save-window-excursion
+ (if (eq major-mode 'mew-message-mode)
+ (mew-message-goto-summary))
+ (let* ((msgnum (mew-summary-message-number2))
+ (mark-info (mew-summary-get-mark)))
+ (if (and org-mew-link-to-refile-destination
+ (eq mark-info ?o)) ; marked as refile
+ (mew-case-folder (mew-sinfo-get-case)
+ (nth 1 (mew-refile-get msgnum)))
+ (let ((folder-or-path (mew-summary-folder-name)))
+ (mew-folder-path-to-folder folder-or-path t))))))
+
+(defun org-mew-open (path)
+ "Follow the Mew message link specified by PATH."
+ (let (folder message-id)
+ (cond ((string-match "\\`\\(+.*\\)+\\+\\([0-9]+\\)\\'" path) ; for Bastien's
+ (setq folder (match-string 1 path))
+ (setq message-id (match-string 2 path)))
+ ((string-match "\\`\\(\\(%#\\)?[^#]+\\)\\(#\\(.*\\)\\)?" path)
+ (setq folder (match-string 1 path))
+ (setq message-id (match-string 4 path)))
+ ((and org-mew-use-id-db (string-match "\\`#\\(.+\\)" path))
+ (setq folder nil)
+ (setq message-id (match-string 1 path)))
+ (t (error "Error in Mew link")))
+ (require 'mew)
+ (mew-window-push)
+ (unless mew-init-p (mew-init))
+ (if (null folder)
+ (progn
+ (mew t)
+ (org-mew-open-by-message-id message-id))
+ (or (org-mew-follow-link folder message-id)
+ (and org-mew-inbox-folder (not (string= org-mew-inbox-folder folder))
+ (org-mew-follow-link org-mew-inbox-folder message-id))
+ (and org-mew-use-id-db
+ (org-mew-open-by-message-id message-id))
+ (error "Message not found")))))
+
+(defun org-mew-follow-link (folder message-id)
+ (unless (org-mew-folder-exists-p folder)
+ (error "No such folder or wrong folder %s" folder))
+ (mew-summary-visit-folder folder)
+ (when message-id
+ (let ((msgnum (org-mew-get-msgnum folder message-id)))
+ (when (mew-summary-search-msg msgnum)
+ (if mew-summary-goto-line-then-display
+ (mew-summary-display))
+ t))))
+
+(defun org-mew-folder-exists-p (folder)
+ (let ((dir (mew-expand-folder folder)))
+ (cond
+ ((mew-folder-virtualp folder) (get-buffer folder))
+ ((null dir) nil)
+ ((mew-folder-remotep (mew-case:folder-folder folder)) t)
+ (t (file-directory-p dir)))))
+
+(defun org-mew-get-msgnum (folder message-id)
+ (if (string-match "\\`[0-9]+\\'" message-id)
+ message-id
+ (let* ((pattern (concat "message-id=" message-id))
+ (msgs (mew-summary-pick-with-mewl pattern folder nil)))
+ (car msgs))))
+
+(defun org-mew-open-by-message-id (message-id)
+ "Open message using ID database."
+ (let ((result (mew-summary-diag-global (format "<%s>" message-id)
+ "-p" "Message")))
+ (unless (eq result t)
+ (error "Message not found"))))
+
+;; In ~/.mew.el, add the following line:
+;; (define-key mew-summary-mode-map "'" 'org-mew-search)
+(defun org-mew-search (&optional arg)
+ "Show all entries related to the message using `org-search-view'.
+
+It shows entries which contains the message ID, the reference
+IDs, or the subject of the message.
+
+With C-u prefix, search for the entries that contains the message
+ID or any of the reference IDs. With C-u C-u prefix, search for
+the message ID or the last reference ID.
+
+The search phase for the subject is extracted with
+`org-mew-subject-alist', which defines the regular expression of
+the subject and the group number to extract. You can get rid of
+\"Re:\" and some other prefix from the subject text."
+ (interactive "P")
+ (when (memq major-mode '(mew-summary-mode mew-virtual-mode))
+ (let ((last-reference-only (equal arg '(16)))
+ (by-subject (null arg))
+ (msgnum (mew-summary-message-number2))
+ (folder-name (mew-summary-folder-name))
+ subject message-id references id-list)
+ (save-window-excursion
+ (if (fboundp 'mew-summary-set-message-buffer)
+ (mew-summary-set-message-buffer folder-name msgnum)
+ (set-buffer (mew-cache-hit folder-name msgnum t)))
+ (setq subject (mew-header-get-value "Subject:"))
+ (setq message-id (mew-header-get-value "Message-Id:"))
+ (setq references (mew-header-get-value "References:")))
+ (setq id-list (mapcar (lambda (id) (org-remove-angle-brackets id))
+ (mew-idstr-to-id-list references)))
+ (if last-reference-only
+ (setq id-list (last id-list))
+ (if message-id
+ (setq id-list (cons (org-remove-angle-brackets message-id)
+ id-list))))
+ (when (and by-subject (stringp subject))
+ (catch 'matched
+ (mapc (lambda (elem)
+ (let ((regexp (car elem))
+ (num (cdr elem)))
+ (when (string-match regexp subject)
+ (setq subject (match-string num subject))
+ (throw 'matched t))))
+ org-mew-subject-alist))
+ (setq id-list (cons subject id-list)))
+ (cond ((null id-list)
+ (error "No message ID to search."))
+ ((equal (length id-list) 1)
+ (org-search-view nil (car id-list)))
+ (t
+ (org-search-view nil (format "{\\(%s\\)}"
+ (mapconcat 'regexp-quote
+ id-list "\\|"))))))
+ (delete-other-windows)))
+
+(defun org-mew-capture (arg)
+ "Guess the capture template from the folder name and invoke `org-capture'.
+
+This selects a capture template in `org-capture-templates' by
+searching for capture template selection keys defined in
+`org-mew-capture-guess-alist' which are associated with the
+regular expression that matches the message's folder name, and
+then invokes `org-capture'.
+
+If the message's folder is a inbox folder, you are prompted to
+put the refile mark on the message and the capture template is
+guessed from the refile destination folder. You can customize
+the inbox folders by `org-mew-capture-inbox-folders'.
+
+If ARG is non-nil, this does not guess the capture template but
+asks you to select the capture template."
+ (interactive "P")
+ (or (not (member (org-mew-folder-name)
+ org-mew-capture-inbox-folders))
+ (eq (mew-summary-get-mark) ?o)
+ (save-window-excursion
+ (if (eq major-mode 'mew-message-mode)
+ (mew-message-goto-summary))
+ (let ((mew-mark-afterstep-spec '((?o 0 0 0 0 0 0 0))))
+ (mew-summary-refile)))
+ (error "No refile folder selected."))
+ (let* ((org-mew-link-to-refile-destination t)
+ (folder-name (org-mew-folder-name))
+ (keys (if arg
+ nil
+ (org-mew-capture-guess-selection-keys folder-name))))
+ (org-capture nil keys)))
+
+(defun org-mew-capture-guess-selection-keys (folder-name)
+ (catch 'found
+ (let ((alist org-mew-capture-guess-alist))
+ (while alist
+ (let ((elem (car alist)))
+ (if (string-match (car elem) folder-name)
+ (throw 'found (cdr elem))))
+ (setq alist (cdr alist))))))
+
+(provide 'org-mew)
+
+;;; org-mew.el ends here
diff --git a/contrib/lisp/org-mime.el b/contrib/lisp/org-mime.el
index fc333be..855dc2d 100644
--- a/contrib/lisp/org-mime.el
+++ b/contrib/lisp/org-mime.el
@@ -1,6 +1,6 @@
;;; org-mime.el --- org html export for text/html MIME emails
-;; Copyright (C) 2010-2012 Eric Schulte
+;; Copyright (C) 2010-2013 Eric Schulte
;; Author: Eric Schulte
;; Keywords: mime, mail, email, html
@@ -22,9 +22,7 @@
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
@@ -57,6 +55,9 @@
;;; Code:
(require 'cl)
+(declare-function org-export-string-as "ox"
+ (string backend &optional body-only ext-plist))
+
(defcustom org-mime-use-property-inheritance nil
"Non-nil means al MAIL_ properties apply also for sublevels."
:group 'org-mime
@@ -195,6 +196,8 @@ and images in a multipart/related part."
html using `org-mode'. If called with an active region only
export that region, otherwise export the entire body."
(interactive "P")
+ (require 'ox-org)
+ (require 'ox-html)
(let* ((region-p (org-region-active-p))
(html-start (or (and region-p (region-beginning))
(save-excursion
@@ -204,10 +207,11 @@ export that region, otherwise export the entire body."
(html-end (or (and region-p (region-end))
;; TODO: should catch signature...
(point-max)))
- (raw-body (buffer-substring html-start html-end))
+ (raw-body (concat org-mime-default-header
+ (buffer-substring html-start html-end)))
(tmp-file (make-temp-name (expand-file-name
"mail" temporary-file-directory)))
- (body (org-export-string raw-body 'org (file-name-directory tmp-file)))
+ (body (org-export-string-as raw-body 'org t))
;; because we probably don't want to skip part of our mail
(org-export-skip-text-before-1st-heading nil)
;; because we probably don't want to export a huge style file
@@ -219,8 +223,7 @@ export that region, otherwise export the entire body."
;; to hold attachments for inline html images
(html-and-images
(org-mime-replace-images
- (org-export-string raw-body 'html (file-name-directory tmp-file))
- tmp-file))
+ (org-export-string-as raw-body 'html t) tmp-file))
(html-images (unless arg (cdr html-and-images)))
(html (org-mime-apply-html-hook
(if arg
@@ -295,26 +298,29 @@ export that region, otherwise export the entire body."
(let ((fmt (if (symbolp fmt) fmt (intern fmt))))
(cond
((eq fmt 'org)
- (insert (org-export-string (org-babel-trim (bhook body 'org)) 'org)))
+ (require 'ox-org)
+ (insert (org-export-string-as
+ (org-babel-trim (bhook body 'org)) 'org t)))
((eq fmt 'ascii)
- (insert (org-export-string
- (concat "#+Title:\n" (bhook body 'ascii)) 'ascii)))
+ (require 'ox-ascii)
+ (insert (org-export-string-as
+ (concat "#+Title:\n" (bhook body 'ascii)) 'ascii t)))
((or (eq fmt 'html) (eq fmt 'html-ascii))
+ (require 'ox-ascii)
+ (require 'ox-org)
(let* ((org-link-file-path-type 'absolute)
;; we probably don't want to export a huge style file
(org-export-htmlize-output-type 'inline-css)
- (html-and-images (org-mime-replace-images
- (org-export-string
- (bhook body 'html)
- 'html (file-name-nondirectory file))
- file))
+ (html-and-images
+ (org-mime-replace-images
+ (org-export-string-as (bhook body 'html) 'html t) file))
(images (cdr html-and-images))
(html (org-mime-apply-html-hook (car html-and-images))))
(insert (org-mime-multipart
- (org-export-string
+ (org-export-string-as
(org-babel-trim
(bhook body (if (eq fmt 'html) 'org 'ascii)))
- (if (eq fmt 'html) 'org 'ascii))
+ (if (eq fmt 'html) 'org 'ascii) t)
html)
(mapconcat 'identity images "\n"))))))))
diff --git a/contrib/lisp/org-mtags.el b/contrib/lisp/org-mtags.el
index 8ea5fa9..dadcef7 100644
--- a/contrib/lisp/org-mtags.el
+++ b/contrib/lisp/org-mtags.el
@@ -1,6 +1,6 @@
;;; org-mtags.el --- Muse-like tags in Org-mode
-;; Copyright (C) 2008-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
;;
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -9,20 +9,18 @@
;;
;; This file is not yet part of GNU Emacs.
;;
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
diff --git a/contrib/lisp/org-notify.el b/contrib/lisp/org-notify.el
index 9ddf150..4047448 100644
--- a/contrib/lisp/org-notify.el
+++ b/contrib/lisp/org-notify.el
@@ -1,10 +1,12 @@
;;; org-notify.el --- Notifications for Org-mode
-;; Copyright (C) 2012 Free Software Foundation, Inc.
+;; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
;; Author: Peter Münster <pmrb@free.fr>
;; Keywords: notification, todo-list, alarm, reminder, pop-up
+;; This file is not part of GNU Emacs.
+
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
@@ -35,6 +37,7 @@
;; (org-notify-start)
;; Example setup:
+;;
;; (org-notify-add 'appt
;; '(:time "-1s" :period "20s" :duration 10
;; :actions (-message -ding))
@@ -42,11 +45,12 @@
;; :actions -notify)
;; '(:time "2h" :period "5m" :actions -message)
;; '(:time "3d" :actions -email))
+;;
;; This means for todo-items with `notify' property set to `appt': 3 days
;; before deadline, send a reminder-email, 2 hours before deadline, start to
;; send messages every 5 minutes, then 15 minutes before deadline, start to
-;; pop up notification windows every 2 minutes. The timeout of the window is
-;; set to 100 seconds. Finally, when deadline is overdue, send messages and
+;; pop up notification windows every 2 minutes. The timeout of the window is
+;; set to 100 seconds. Finally, when deadline is overdue, send messages and
;; make noise."
;; Take also a look at the function `org-notify-add'.
@@ -104,12 +108,21 @@
(cdr (assoc (match-string 3 str) conv))
(if (= (length (match-string 1 str)) 1) -1 1)))))
+(defun org-notify-convert-deadline (orig)
+ "Convert original deadline from `org-element-parse-buffer' to
+simple timestamp string."
+ (if orig
+ (replace-regexp-in-string "^<\\|>$" ""
+ (plist-get (plist-get orig 'timestamp)
+ :raw-value))))
+
(defun org-notify-make-todo (heading &rest ignored)
"Create one todo item."
(macrolet ((get (k) `(plist-get list ,k))
(pr (k v) `(setq result (plist-put result ,k ,v))))
(let* ((list (nth 1 heading)) (notify (or (get :notify) "default"))
- (deadline (get :deadline)) (heading (get :raw-value))
+ (deadline (org-notify-convert-deadline (get :deadline)))
+ (heading (get :raw-value))
result)
(when (and (eq (get :todo-type) 'todo) heading deadline)
(pr :heading heading) (pr :notify (intern notify))
@@ -173,26 +186,29 @@ forgotten tasks."
(return)))))))
(defun org-notify-add (name &rest params)
- "Add a new notification type. The NAME can be used in Org-mode property
-`notify'. If NAME is `default', the notification type applies for todo items
-without the `notify' property. This file predefines such a default
+ "Add a new notification type.
+The NAME can be used in Org-mode property `notify'. If NAME is
+`default', the notification type applies for todo items without
+the `notify' property. This file predefines such a default
notification type.
Each element of PARAMS is a list with parameters for a given time
-distance to the deadline. This distance must increase from one element to
-the next.
+distance to the deadline. This distance must increase from one
+element to the next.
+
List of possible parameters:
+
:time Time distance to deadline, when this type of notification shall
- start. It's a string: an integral value (positive or negative)
+ start. It's a string: an integral value (positive or negative)
followed by a unit (s, m, h, d, w, M).
:actions A function or a list of functions to be called to notify the
- user. Instead of a function name, you can also supply a suffix
+ user. Instead of a function name, you can also supply a suffix
of one of the various predefined `org-notify-action-xxx'
functions.
- :period Optional: can be used to repeat the actions periodically. Same
- format as :time.
+ :period Optional: can be used to repeat the actions periodically.
+ Same format as :time.
:duration Some actions use this parameter to specify the duration of the
- notification. It's an integral number in seconds.
+ notification. It's an integral number in seconds.
:audible Overwrite the value of `org-notify-audible' for this action.
For the actions, you can use your own functions or some of the predefined
@@ -200,11 +216,12 @@ ones, whose names are prefixed with `org-notify-action-'."
(setq org-notify-map (plist-put org-notify-map name params)))
(defun org-notify-start (&optional secs)
- "Start the notification daemon. If SECS is positive, it's the
-period in seconds for processing the notifications of one
-org-agenda file, and if negative, notifications will be checked
-only when emacs is idle for -SECS seconds. The default value for
-SECS is 20."
+ "Start the notification daemon.
+If SECS is positive, it's the period in seconds for processing
+the notifications of one org-agenda file, and if negative,
+notifications will be checked only when emacs is idle for -SECS
+seconds. The default value for SECS is 20."
+ (interactive)
(if org-notify-timer
(org-notify-stop))
(setq secs (or secs 20)
@@ -216,8 +233,8 @@ SECS is 20."
(defun org-notify-stop ()
"Stop the notification daemon."
(when org-notify-timer
- (cancel-timer org-notify-timer)
- (setq org-notify-timer nil)))
+ (cancel-timer org-notify-timer)
+ (setq org-notify-timer nil)))
(defun org-notify-on-action (plist key)
"User wants to see action."
@@ -299,7 +316,7 @@ SECS is 20."
(defun org-notify-select-highest-window ()
"Select the highest window on the frame, that is not is not an
-org-notify window. Mostly copied from `appt-select-lowest-window'."
+org-notify window. Mostly copied from `appt-select-lowest-window'."
(let ((highest-window (selected-window))
(bottom-edge (nth 3 (window-edges)))
next-bottom-edge)
@@ -370,7 +387,7 @@ terminal an emacs window."
;;; Provide a minimal default setup.
(org-notify-add 'default '(:time "1h" :actions -notify/window
- :period "2m" :duration 60))
+ :period "2m" :duration 60))
(provide 'org-notify)
diff --git a/contrib/lisp/org-notmuch.el b/contrib/lisp/org-notmuch.el
index 0affd71..c7f92fe 100644
--- a/contrib/lisp/org-notmuch.el
+++ b/contrib/lisp/org-notmuch.el
@@ -1,6 +1,6 @@
;;; org-notmuch.el --- Support for links to notmuch messages from within Org-mode
-;; Copyright (C) 2010-2012 Matthieu Lemerre
+;; Copyright (C) 2010-2013 Matthieu Lemerre
;; Author: Matthieu Lemerre <racin@free.fr>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -19,9 +19,7 @@
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/contrib/lisp/org-panel.el b/contrib/lisp/org-panel.el
index 3ffdfaf..dec7241 100644
--- a/contrib/lisp/org-panel.el
+++ b/contrib/lisp/org-panel.el
@@ -50,9 +50,7 @@
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
-;; along with this program; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
-;; Floor, Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -133,8 +131,6 @@ active.)"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Hook functions etc
-;;(defvar orgpan-this-panel-window nil)
-
(defun orgpan-delete-panel ()
"Remove the panel."
(interactive)
@@ -203,8 +199,7 @@ active.)"
(unless (and orgpan-point
(= (point) orgpan-point))
;; Go backward so it is possible to click on a "button":
- (orgpan-backward-field)))))
- (setq orgpan-this-panel-window nil))
+ (orgpan-backward-field))))))
(error (lwarn 't :warning "orgpan-post: %S" err))))
;; (defun orgpan-window-config-change ()
@@ -294,7 +289,7 @@ active.)"
(defun orgpan-check-panel-mode ()
(unless (derived-mode-p 'orgpan-mode)
- (error "Not orgpan-mode in buffer: " major-mode)))
+ (error "Not orgpan-mode in buffer: %s" major-mode)))
(defun orgpan-display-bindings-help ()
(orgpan-check-panel-mode)
@@ -401,6 +396,9 @@ There can be only one such buffer at any time.")
(defvar orgpan-point nil)
;;(make-variable-buffer-local 'orgpan-point)
+(defvar viper-emacs-state-mode-list)
+(defvar viper-new-major-mode-buffer-list)
+
(defun orgpan-avoid-viper-in-buffer ()
;; Fix-me: This is ugly. However see `this-major-mode-requires-vi-state':
(set (make-local-variable 'viper-emacs-state-mode-list) '(orgpan-mode))
@@ -598,12 +596,11 @@ button changes the binding of the arrow keys."
org-mode-map))
;;(org-back-to-heading)
;;(remove-hook 'window-configuration-change-hook 'orgpan-window-config-change)
- (split-window)
+ (setq orgpan-org-window (selected-window))
+ (setq orgpan-panel-window (split-window nil -4 'below))
+ (select-window orgpan-panel-window)
(set-window-buffer (selected-window) (orgpan-make-panel-buffer))
- (setq orgpan-panel-window (selected-window))
;;(set-window-dedicated-p (selected-window) t)
- (fit-window-to-buffer nil nil 3)
- (setq orgpan-org-window (next-window))
;; The minor mode version starts here:
(when orgpan-minor-mode-version
(select-window orgpan-org-window)
diff --git a/contrib/lisp/org-registry.el b/contrib/lisp/org-registry.el
index c1a1c6c..1950797 100644
--- a/contrib/lisp/org-registry.el
+++ b/contrib/lisp/org-registry.el
@@ -1,6 +1,6 @@
;;; org-registry.el --- a registry for Org links
;;
-;; Copyright 2007-2012 Bastien Guerry
+;; Copyright 2007-2013 Bastien Guerry
;;
;; Emacs Lisp Archive Entry
;; Filename: org-registry.el
@@ -11,6 +11,8 @@
;; Description: Shows Org files where the current buffer is linked
;; URL: http://www.cognition.ens.fr/~guerry/u/org-registry.el
;;
+;; This file is not part of GNU Emacs.
+;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
@@ -22,8 +24,7 @@
;; 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, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
diff --git a/contrib/lisp/org-screen.el b/contrib/lisp/org-screen.el
index a517b4b..3334a0f 100644
--- a/contrib/lisp/org-screen.el
+++ b/contrib/lisp/org-screen.el
@@ -1,26 +1,24 @@
;;; org-screen.el --- Integreate Org-mode with screen.
-;; Copyright (c) 2008-2012 Andrew Hyatt
+;; Copyright (c) 2008-2013 Andrew Hyatt
;;
;; Author: Andrew Hyatt <ahyatt at gmail dot com>
;; Maintainer: Carsten Dominik <carsten at orgmode dot org>
;;
;; This file is not yet part of GNU Emacs.
;;
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
diff --git a/contrib/lisp/org-secretary.el b/contrib/lisp/org-secretary.el
index 5db60f6..e98eb34 100644
--- a/contrib/lisp/org-secretary.el
+++ b/contrib/lisp/org-secretary.el
@@ -1,5 +1,5 @@
;;; org-secretary.el --- Team management with org-mode
-;; Copyright (C) 2010-2012 Juan Reyero
+;; Copyright (C) 2010-2013 Juan Reyero
;;
;; Author: Juan Reyero <juan _at_ juanreyero _dot_ com>
;; Keywords: outlines, tasks, team, management
@@ -19,9 +19,7 @@
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
diff --git a/contrib/lisp/org-static-mathjax.el b/contrib/lisp/org-static-mathjax.el
index 29f2cfe..ac13ee2 100644
--- a/contrib/lisp/org-static-mathjax.el
+++ b/contrib/lisp/org-static-mathjax.el
@@ -2,6 +2,22 @@
;;
;; Author: Jan Böker <jan dot boecker at jboecker dot de>
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
;; This elisp code integrates Static MathJax into the
;; HTML export process of Org-mode.
;;
@@ -39,7 +55,7 @@
;; of your math, add the following line at the top of your Org file:
;; -*- coding: utf-8; -*-
;;
-;; License: GPL v2 or later
+;;; Code:
(defcustom org-static-mathjax-app-ini-path
(or (expand-file-name
diff --git a/contrib/lisp/org-sudoku.el b/contrib/lisp/org-sudoku.el
index 6977f1f..2bf24d8 100644
--- a/contrib/lisp/org-sudoku.el
+++ b/contrib/lisp/org-sudoku.el
@@ -1,6 +1,6 @@
;;; org-sudoku.el --- Greate and solve SUDOKU games in Org tables
-;; Copyright (C) 2012 Free Software Foundation, Inc.
+;; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
;;
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp, games
@@ -9,20 +9,18 @@
;;
;; This file is not yet part of GNU Emacs.
;;
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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, or (at your option)
;; any later version.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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 GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
diff --git a/contrib/lisp/org-toc.el b/contrib/lisp/org-toc.el
index 3f37cb8..e0e6098 100644
--- a/contrib/lisp/org-toc.el
+++ b/contrib/lisp/org-toc.el
@@ -1,6 +1,6 @@
;;; org-toc.el --- Table of contents for Org-mode buffer
-;; Copyright 2007-2012 Free Software Foundation, Inc.
+;; Copyright 2007-2013 Free Software Foundation, Inc.
;;
;; Author: Bastien Guerry <bzg AT gnu DOT org>
;; Keywords: Org table of contents
@@ -20,8 +20,7 @@
;; 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, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
@@ -110,7 +109,7 @@ echo-area. The COLUMNS property is always exluded."
(setq major-mode 'org-toc-mode))
;; toggle modes
-(define-key org-toc-mode-map "f" 'org-toc-follow-mode)
+(define-key org-toc-mode-map "F" 'org-toc-follow-mode)
(define-key org-toc-mode-map "S" 'org-toc-show-subtree-mode)
(define-key org-toc-mode-map "s" 'org-toc-store-config)
(define-key org-toc-mode-map "g" 'org-toc-restore-config)
@@ -120,8 +119,10 @@ echo-area. The COLUMNS property is always exluded."
;; navigation keys
(define-key org-toc-mode-map "p" 'org-toc-previous)
(define-key org-toc-mode-map "n" 'org-toc-next)
-(define-key org-toc-mode-map [(left)] 'org-toc-previous)
-(define-key org-toc-mode-map [(right)] 'org-toc-next)
+(define-key org-toc-mode-map "f" 'org-toc-forward)
+(define-key org-toc-mode-map "b" 'org-toc-back)
+(define-key org-toc-mode-map [(left)] 'org-toc-back)
+(define-key org-toc-mode-map [(right)] 'org-toc-forward)
(define-key org-toc-mode-map [(up)] 'org-toc-previous)
(define-key org-toc-mode-map [(down)] 'org-toc-next)
(define-key org-toc-mode-map "1" (lambda() (interactive) (org-toc-show 1 (point))))
@@ -332,6 +333,24 @@ If DELETE is non-nil, delete other windows when in the Org buffer."
(if org-toc-info-mode (org-toc-info))
(if org-toc-follow-mode (org-toc-goto)))
+(defun org-toc-forward ()
+ "Go to the next headline at the same level in the TOC."
+ (interactive)
+ (condition-case nil
+ (outline-forward-same-level 1)
+ (error (message "No next headline at this level.")))
+ (if org-toc-info-mode (org-toc-info))
+ (if org-toc-follow-mode (org-toc-goto)))
+
+(defun org-toc-back ()
+ "Go to the previous headline at the same level in the TOC."
+ (interactive)
+ (condition-case nil
+ (outline-backward-same-level 1)
+ (error (message "No previous headline at this level.")))
+ (if org-toc-info-mode (org-toc-info))
+ (if org-toc-follow-mode (org-toc-goto)))
+
(defun org-toc-quit ()
"Quit the current Org TOC buffer."
(interactive)
@@ -462,12 +481,13 @@ status."
(let ((st-start 0)
(help-message
"\[space\] show heading \[1-4\] hide headlines below this level
-\[TAB\] jump to heading \[f\] toggle follow mode (currently %s)
+\[TAB\] jump to heading \[F\] toggle follow mode (currently %s)
\[return\] jump and delete others windows \[i\] toggle info mode (currently %s)
\[S-TAB\] cycle subtree (in Org) \[S\] toggle show subtree mode (currently %s)
\[C-S-TAB\] global cycle (in Org) \[r\] toggle recenter mode (currently %s)
\[:\] cycle subtree (in TOC) \[c\] toggle column view (currently %s)
\[n/p\] next/previous heading \[s\] save TOC configuration
+\[f/b\] next/previous heading of same level
\[q\] quit the TOC \[g\] restore last TOC configuration"))
(while (string-match "\\[[^]]+\\]" help-message st-start)
(add-text-properties (match-beginning 0)
diff --git a/contrib/lisp/org-track.el b/contrib/lisp/org-track.el
index 1d12862..db8c34e 100644
--- a/contrib/lisp/org-track.el
+++ b/contrib/lisp/org-track.el
@@ -1,6 +1,6 @@
;;; org-track.el --- Track the most recent Org-mode version available.
;;
-;; Copyright (C) 2009-2012
+;; Copyright (C) 2009-2013
;; Free Software Foundation, Inc.
;;
;; Author: Bastien Guerry <bzg at altern dot org>
@@ -16,12 +16,12 @@
;;
;; This file is not part of GNU Emacs.
;;
-;; GNU Emacs is free software: you can redistribute it and/or modify
+;; 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.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
@@ -32,6 +32,9 @@
;;
;;; Commentary:
;;
+;; WARNING: This library is obsolete, you should use the make targets
+;; to keep track of Org latest developments.
+;;
;; Download the latest development tarball, unpack and optionally compile it
;;
;; Usage:
@@ -46,15 +49,11 @@
;;
;; M-x org-track-update RET
-
-
(require 'url-parse)
(require 'url-handlers)
(autoload 'url-file-local-copy "url-handlers")
(autoload 'url-generic-parse-url "url-parse")
-
-
;;; Variables:
@@ -66,21 +65,20 @@ To use org-track, adjust `org-track-directory'.
Org will download the archived latest git version for you,
unpack it into that directory (i.e. a subdirectory
`org-mode/' is added), create the autoloads file
-`org-install.el' for you and, optionally, compile the
+`org-loaddefs.el' for you and, optionally, compile the
sources.
All you'll have to do is call `M-x org-track-update' from
time to time."
- :version "22.1"
:group 'org)
-(defcustom org-track-directory "~/.emacs.d/org/lisp"
+(defcustom org-track-directory (concat user-emacs-directory "org/lisp")
"Directory where your org-mode/ directory lives.
If that directory does not exist, it will be created."
:type 'directory)
(defcustom org-track-compile-sources t
"If `nil', never compile org-sources.
-Org will only create the autoloads file `org-install.el' for
+Org will only create the autoloads file `org-loaddefs.el' for
you then. If `t', compile the sources, too.
Note, that emacs preferes compiled elisp files over
non-compiled ones."
@@ -102,8 +100,6 @@ you need to unpack it."
"Remove org-latest.tar.gz after updates?"
:type 'boolean)
-
-
;;; Frontend
@@ -131,7 +127,6 @@ Also, generate autoloads and evtl. compile the sources."
(org-track-compile-org))
(error (message "%s" (error-message-string err)))))))
-
;;; tar related functions
@@ -171,7 +166,6 @@ subdirectory org-mode/ to DIRECTORY."
(if org-track-remove-package
(delete-file target))))
-
;;; Compile Org-mode sources
@@ -180,7 +174,7 @@ subdirectory org-mode/ to DIRECTORY."
;;;###autoload
(defun org-track-compile-org (&optional directory)
"Compile all *.el files that come with org-mode.
-Generate the autoloads file `org-install.el'.
+Generate the autoloads file `org-loaddefs.el'.
DIRECTORY is where the directory org-mode/ lives (i.e. the
parent directory of your local repo."
@@ -193,15 +187,15 @@ DIRECTORY is where the directory org-mode/ lives (i.e. the
"/")))
(add-to-list 'load-path directory)
(let ((list-of-org-files (file-expand-wildcards (concat directory "*.el"))))
- ;; create the org-install file
+ ;; create the org-loaddefs file
(require 'autoload)
- (setq esf/org-install-file (concat directory "org-install.el"))
+ (setq esf/org-install-file (concat directory "org-loaddefs.el"))
(find-file esf/org-install-file)
(erase-buffer)
(mapc (lambda (x)
(generate-file-autoloads x))
list-of-org-files)
- (insert "\n(provide (quote org-install))\n")
+ (insert "\n(provide (quote org-loaddefs))\n")
(save-buffer)
(kill-buffer)
(byte-compile-file esf/org-install-file t)
@@ -213,7 +207,6 @@ DIRECTORY is where the directory org-mode/ lives (i.e. the
(if org-track-compile-sources
(mapc (lambda (f) (byte-compile-file f)) list-of-org-files))))
-
(provide 'org-track)
;;; org-track.el ends here
diff --git a/contrib/lisp/org-velocity.el b/contrib/lisp/org-velocity.el
index 7425d32..fa41406 100644
--- a/contrib/lisp/org-velocity.el
+++ b/contrib/lisp/org-velocity.el
@@ -1,6 +1,6 @@
;;; org-velocity.el --- something like Notational Velocity for Org.
-;; Copyright (C) 2010-2012 Paul M. Rodriguez
+;; Copyright (C) 2010-2013 Paul M. Rodriguez
;; Author: Paul M. Rodriguez <paulmrodriguez@gmail.com>
;; Created: 2010-05-05
@@ -17,9 +17,8 @@
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
-;; For a copy of the GNU General Public License, search the Internet,
-;; or write to the Free Software Foundation, Inc., 59 Temple Place,
-;; Suite 330, Boston, MA 02111-1307 USA
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Org-Velocity.el is an interface for Org inspired by the minimalist
diff --git a/contrib/lisp/org-vm.el b/contrib/lisp/org-vm.el
new file mode 100644
index 0000000..f60c5bb
--- /dev/null
+++ b/contrib/lisp/org-vm.el
@@ -0,0 +1,180 @@
+;;; org-vm.el --- Support for links to VM messages from within Org-mode
+
+;; Copyright (C) 2004-2013 Free Software Foundation, Inc.
+
+;; Author: Carsten Dominik <carsten at orgmode dot org>
+;; Keywords: outlines, hypermedia, calendar, wp
+;; Homepage: http://orgmode.org
+;;
+;; Support for IMAP folders added
+;; by Konrad Hinsen <konrad dot hinsen at fastmail dot net>
+;; Requires VM 8.2.0a or later.
+;;
+;; This file is not part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+;; This file implements links to VM messages and folders from within Org-mode.
+;; Org-mode loads this module by default - if this is not what you want,
+;; configure the variable `org-modules'.
+
+;;; Code:
+
+(require 'org)
+
+;; Declare external functions and variables
+(declare-function vm-preview-current-message "ext:vm-page" ())
+(declare-function vm-follow-summary-cursor "ext:vm-motion" ())
+(declare-function vm-get-header-contents "ext:vm-summary"
+ (message header-name-regexp &optional clump-sep))
+(declare-function vm-isearch-narrow "ext:vm-search" ())
+(declare-function vm-isearch-update "ext:vm-search" ())
+(declare-function vm-select-folder-buffer "ext:vm-macro" ())
+(declare-function vm-su-message-id "ext:vm-summary" (m))
+(declare-function vm-su-subject "ext:vm-summary" (m))
+(declare-function vm-summarize "ext:vm-summary" (&optional display raise))
+(declare-function vm-imap-folder-p "ext:vm-save" ())
+(declare-function vm-imap-find-spec-for-buffer "ext:vm-imap" (buffer))
+(declare-function vm-imap-folder-for-spec "ext:vm-imap" (spec))
+(declare-function vm-imap-parse-spec-to-list "ext:vm-imap" (spec))
+(declare-function vm-imap-spec-for-account "ext:vm-imap" (account))
+(defvar vm-message-pointer)
+(defvar vm-folder-directory)
+
+;; Install the link type
+(org-add-link-type "vm" 'org-vm-open)
+(org-add-link-type "vm-imap" 'org-vm-imap-open)
+(add-hook 'org-store-link-functions 'org-vm-store-link)
+
+;; Implementation
+(defun org-vm-store-link ()
+ "Store a link to a VM folder or message."
+ (when (and (or (eq major-mode 'vm-summary-mode)
+ (eq major-mode 'vm-presentation-mode))
+ (save-window-excursion
+ (vm-select-folder-buffer) buffer-file-name))
+ (and (eq major-mode 'vm-presentation-mode) (vm-summarize))
+ (vm-follow-summary-cursor)
+ (save-excursion
+ (vm-select-folder-buffer)
+ (let* ((message (car vm-message-pointer))
+ (subject (vm-su-subject message))
+ (to (vm-get-header-contents message "To"))
+ (from (vm-get-header-contents message "From"))
+ (message-id (vm-su-message-id message))
+ (link-type (if (vm-imap-folder-p) "vm-imap" "vm"))
+ (date (vm-get-header-contents message "Date"))
+ (date-ts (and date (format-time-string
+ (org-time-stamp-format t)
+ (date-to-time date))))
+ (date-ts-ia (and date (format-time-string
+ (org-time-stamp-format t t)
+ (date-to-time date))))
+ folder desc link)
+ (if (vm-imap-folder-p)
+ (let ((spec (vm-imap-find-spec-for-buffer (current-buffer))))
+ (setq folder (vm-imap-folder-for-spec spec)))
+ (progn
+ (setq folder (abbreviate-file-name buffer-file-name))
+ (if (and vm-folder-directory
+ (string-match (concat "^" (regexp-quote vm-folder-directory))
+ folder))
+ (setq folder (replace-match "" t t folder)))))
+ (setq message-id (org-remove-angle-brackets message-id))
+ (org-store-link-props :type link-type :from from :to to :subject subject
+ :message-id message-id)
+ (when date
+ (org-add-link-props :date date :date-timestamp date-ts
+ :date-timestamp-inactive date-ts-ia))
+ (setq desc (org-email-link-description))
+ (setq link (concat (concat link-type ":") folder "#" message-id))
+ (org-add-link-props :link link :description desc)
+ link))))
+
+(defun org-vm-open (path)
+ "Follow a VM message link specified by PATH."
+ (let (folder article)
+ (if (not (string-match "\\`\\([^#]+\\)\\(#\\(.*\\)\\)?" path))
+ (error "Error in VM link"))
+ (setq folder (match-string 1 path)
+ article (match-string 3 path))
+ ;; The prefix argument will be interpreted as read-only
+ (org-vm-follow-link folder article current-prefix-arg)))
+
+(defun org-vm-follow-link (&optional folder article readonly)
+ "Follow a VM link to FOLDER and ARTICLE."
+ (require 'vm)
+ (setq article (org-add-angle-brackets article))
+ (if (string-match "^//\\([a-zA-Z]+@\\)?\\([^:]+\\):\\(.*\\)" folder)
+ ;; ange-ftp or efs or tramp access
+ (let ((user (or (match-string 1 folder) (user-login-name)))
+ (host (match-string 2 folder))
+ (file (match-string 3 folder)))
+ (cond
+ ((featurep 'tramp)
+ ;; use tramp to access the file
+ (if (featurep 'xemacs)
+ (setq folder (format "[%s@%s]%s" user host file))
+ (setq folder (format "/%s@%s:%s" user host file))))
+ (t
+ ;; use ange-ftp or efs
+ (require (if (featurep 'xemacs) 'efs 'ange-ftp))
+ (setq folder (format "/%s@%s:%s" user host file))))))
+ (when folder
+ (funcall (cdr (assq 'vm org-link-frame-setup)) folder readonly)
+ (when article
+ (org-vm-select-message (org-add-angle-brackets article)))))
+
+(defun org-vm-imap-open (path)
+ "Follow a VM link to an IMAP folder."
+ (require 'vm-imap)
+ (when (string-match "\\([^:]+\\):\\([^#]+\\)#?\\(.+\\)?" path)
+ (let* ((account-name (match-string 1 path))
+ (mailbox-name (match-string 2 path))
+ (message-id (match-string 3 path))
+ (account-spec (vm-imap-parse-spec-to-list
+ (vm-imap-spec-for-account account-name)))
+ (mailbox-spec (mapconcat 'identity
+ (append (butlast account-spec 4)
+ (cons mailbox-name
+ (last account-spec 3)))
+ ":")))
+ (funcall (cdr (assq 'vm-imap org-link-frame-setup))
+ mailbox-spec)
+ (when message-id
+ (org-vm-select-message (org-add-angle-brackets message-id))))))
+
+(defun org-vm-select-message (message-id)
+ "Go to the message with message-id in the current folder."
+ (require 'vm-search)
+ (sit-for 0.1)
+ (vm-select-folder-buffer)
+ (widen)
+ (let ((case-fold-search t))
+ (goto-char (point-min))
+ (if (not (re-search-forward
+ (concat "^" "message-id: *" (regexp-quote message-id))))
+ (error "Could not find the specified message in this folder"))
+ (vm-isearch-update)
+ (vm-isearch-narrow)
+ (vm-preview-current-message)
+ (vm-summarize)))
+
+(provide 'org-vm)
+
+
+
+;;; org-vm.el ends here
diff --git a/contrib/lisp/org-wikinodes.el b/contrib/lisp/org-wikinodes.el
index bdc3e34..4efc373 100644
--- a/contrib/lisp/org-wikinodes.el
+++ b/contrib/lisp/org-wikinodes.el
@@ -1,6 +1,6 @@
;;; org-wikinodes.el --- Wiki-like CamelCase links to outline nodes
-;; Copyright (C) 2010-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2010-2013 Free Software Foundation, Inc.
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -9,12 +9,12 @@
;;
;; This file is not part of GNU Emacs.
;;
-;; GNU Emacs is free software: you can redistribute it and/or modify
+;; 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.
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; 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.
@@ -281,30 +281,29 @@ with working links."
link file)
(goto-char (point-min))
(while (re-search-forward re nil t)
- (org-if-unprotected-at (match-beginning 0)
- (unless (save-match-data
- (or (org-at-heading-p)
- (org-in-regexp org-bracket-link-regexp)
- (org-in-regexp org-plain-link-re)
- (org-in-regexp "<<[^<>]+>>")))
- (setq link (match-string 0))
- (delete-region (match-beginning 0) (match-end 0))
- (save-match-data
- (cond
- ((org-find-exact-headline-in-buffer link (current-buffer))
- ;; Found in current buffer
- (insert (format "[[#%s][%s]]" link link)))
- ((eq org-wikinodes-scope 'file)
- ;; No match in file, and other files are not allowed
- (insert (format "%s" link)))
- ((setq file
- (and (org-string-nw-p org-current-export-file)
- (org-wikinodes-which-file
- link (file-name-directory org-current-export-file))))
- ;; Match in another file in the current directory
- (insert (format "[[file:%s::%s][%s]]" file link link)))
- (t ;; No match for this link
- (insert (format "%s" link))))))))))
+ (unless (save-match-data
+ (or (org-at-heading-p)
+ (org-in-regexp org-bracket-link-regexp)
+ (org-in-regexp org-plain-link-re)
+ (org-in-regexp "<<[^<>]+>>")))
+ (setq link (match-string 0))
+ (delete-region (match-beginning 0) (match-end 0))
+ (save-match-data
+ (cond
+ ((org-find-exact-headline-in-buffer link (current-buffer))
+ ;; Found in current buffer
+ (insert (format "[[#%s][%s]]" link link)))
+ ((eq org-wikinodes-scope 'file)
+ ;; No match in file, and other files are not allowed
+ (insert (format "%s" link)))
+ ((setq file
+ (and (org-string-nw-p org-current-export-file)
+ (org-wikinodes-which-file
+ link (file-name-directory org-current-export-file))))
+ ;; Match in another file in the current directory
+ (insert (format "[[file:%s::%s][%s]]" file link link)))
+ (t ;; No match for this link
+ (insert (format "%s" link)))))))))
;;; Hook the WikiNode mechanism into Org
diff --git a/contrib/lisp/org-wl.el b/contrib/lisp/org-wl.el
new file mode 100644
index 0000000..7d685df
--- /dev/null
+++ b/contrib/lisp/org-wl.el
@@ -0,0 +1,311 @@
+;;; org-wl.el --- Support for links to Wanderlust messages from within Org-mode
+
+;; Copyright (C) 2004-2013 Free Software Foundation, Inc.
+
+;; Author: Tokuya Kameshima <kames at fa2 dot so-net dot ne dot jp>
+;; David Maus <dmaus at ictsoc dot de>
+;; Keywords: outlines, hypermedia, calendar, wp
+;; Homepage: http://orgmode.org
+;;
+;; This file is not part of GNU Emacs.
+;;
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+
+;; This file implements links to Wanderlust messages from within Org-mode.
+;; Org-mode loads this module by default - if this is not what you want,
+;; configure the variable `org-modules'.
+
+;;; Code:
+
+(require 'org)
+
+(defgroup org-wl nil
+ "Options concerning the Wanderlust link."
+ :tag "Org Startup"
+ :group 'org-link)
+
+(defcustom org-wl-link-to-refile-destination t
+ "Create a link to the refile destination if the message is marked as refile."
+ :group 'org-wl
+ :type 'boolean)
+
+(defcustom org-wl-link-remove-filter nil
+ "Remove filter condition if message is filter folder."
+ :group 'org-wl
+ :type 'boolean)
+
+(defcustom org-wl-shimbun-prefer-web-links nil
+ "If non-nil create web links for shimbun messages."
+ :group 'org-wl
+ :type 'boolean)
+
+(defcustom org-wl-nntp-prefer-web-links nil
+ "If non-nil create web links for nntp messages.
+When folder name contains string \"gmane\" link to gmane,
+googlegroups otherwise."
+ :type 'boolean
+ :group 'org-wl)
+
+(defcustom org-wl-disable-folder-check t
+ "Disable check for new messages when open a link."
+ :type 'boolean
+ :group 'org-wl)
+
+(defcustom org-wl-namazu-default-index nil
+ "Default namazu search index."
+ :type 'directory
+ :group 'org-wl)
+
+;; Declare external functions and variables
+(declare-function elmo-folder-exists-p "ext:elmo" (folder) t)
+(declare-function elmo-message-entity-field "ext:elmo-msgdb"
+ (entity field &optional type))
+(declare-function elmo-message-field "ext:elmo"
+ (folder number field &optional type) t)
+(declare-function elmo-msgdb-overview-get-entity "ext:elmo" (id msgdb) t)
+;; Backward compatibility to old version of wl
+(declare-function wl "ext:wl" () t)
+(declare-function wl-summary-buffer-msgdb "ext:wl-folder" () t)
+(declare-function wl-summary-jump-to-msg-by-message-id "ext:wl-summary"
+ (&optional id))
+(declare-function wl-summary-jump-to-msg "ext:wl-summary"
+ (&optional number beg end))
+(declare-function wl-summary-line-from "ext:wl-summary" ())
+(declare-function wl-summary-line-subject "ext:wl-summary" ())
+(declare-function wl-summary-message-number "ext:wl-summary" ())
+(declare-function wl-summary-redisplay "ext:wl-summary" (&optional arg))
+(declare-function wl-summary-registered-temp-mark "ext:wl-action" (number))
+(declare-function wl-folder-goto-folder-subr "ext:wl-folder"
+ (&optional folder sticky))
+(declare-function wl-folder-get-petname "ext:wl-folder" (name))
+(declare-function wl-folder-get-entity-from-buffer "ext:wl-folder"
+ (&optional getid))
+(declare-function wl-folder-buffer-group-p "ext:wl-folder")
+(defvar wl-init)
+(defvar wl-summary-buffer-elmo-folder)
+(defvar wl-summary-buffer-folder-name)
+(defvar wl-folder-group-regexp)
+(defvar wl-auto-check-folder-name)
+(defvar elmo-nntp-default-server)
+
+(defconst org-wl-folder-types
+ '(("%" . imap) ("-" . nntp) ("+" . mh) ("=" . spool)
+ ("$" . archive) ("&" . pop) ("@" . shimbun) ("[" . search)
+ ("*" . multi) ("/" . filter) ("|" . pipe) ("'" . internal))
+ "List of folder indicators. See Wanderlust manual, section 3.")
+
+;; Install the link type
+(org-add-link-type "wl" 'org-wl-open)
+(add-hook 'org-store-link-functions 'org-wl-store-link)
+
+;; Implementation
+
+(defun org-wl-folder-type (folder)
+ "Return symbol that indicates the type of FOLDER.
+FOLDER is the wanderlust folder name. The first character of the
+folder name determines the folder type."
+ (let* ((indicator (substring folder 0 1))
+ (type (cdr (assoc indicator org-wl-folder-types))))
+ ;; maybe access or file folder
+ (when (not type)
+ (setq type
+ (cond
+ ((and (>= (length folder) 5)
+ (string= (substring folder 0 5) "file:"))
+ 'file)
+ ((and (>= (length folder) 7)
+ (string= (substring folder 0 7) "access:"))
+ 'access)
+ (t
+ nil))))
+ type))
+
+(defun org-wl-message-field (field entity)
+ "Return content of FIELD in ENTITY.
+FIELD is a symbol of a rfc822 message header field.
+ENTITY is a message entity."
+ (let ((content (elmo-message-entity-field entity field 'string)))
+ (if (listp content) (car content) content)))
+
+(defun org-wl-store-link ()
+ "Store a link to a WL message or folder."
+ (unless (eobp)
+ (cond
+ ((memq major-mode '(wl-summary-mode mime-view-mode))
+ (org-wl-store-link-message))
+ ((eq major-mode 'wl-folder-mode)
+ (org-wl-store-link-folder))
+ (t
+ nil))))
+
+(defun org-wl-store-link-folder ()
+ "Store a link to a WL folder."
+ (let* ((folder (wl-folder-get-entity-from-buffer))
+ (petname (wl-folder-get-petname folder))
+ (link (concat "wl:" folder)))
+ (save-excursion
+ (beginning-of-line)
+ (unless (and (wl-folder-buffer-group-p)
+ (looking-at wl-folder-group-regexp))
+ (org-store-link-props :type "wl" :description petname
+ :link link)
+ link))))
+
+(defun org-wl-store-link-message ()
+ "Store a link to a WL message."
+ (save-excursion
+ (let ((buf (if (eq major-mode 'wl-summary-mode)
+ (current-buffer)
+ (and (boundp 'wl-message-buffer-cur-summary-buffer)
+ wl-message-buffer-cur-summary-buffer))))
+ (when buf
+ (with-current-buffer buf
+ (let* ((msgnum (wl-summary-message-number))
+ (mark-info (wl-summary-registered-temp-mark msgnum))
+ (folder-name
+ (if (and org-wl-link-to-refile-destination
+ mark-info
+ (equal (nth 1 mark-info) "o")) ; marked as refile
+ (nth 2 mark-info)
+ wl-summary-buffer-folder-name))
+ (folder-type (org-wl-folder-type folder-name))
+ (wl-message-entity
+ (if (fboundp 'elmo-message-entity)
+ (elmo-message-entity
+ wl-summary-buffer-elmo-folder msgnum)
+ (elmo-msgdb-overview-get-entity
+ msgnum (wl-summary-buffer-msgdb))))
+ (message-id
+ (org-wl-message-field 'message-id wl-message-entity))
+ (message-id-no-brackets
+ (org-remove-angle-brackets message-id))
+ (from (org-wl-message-field 'from wl-message-entity))
+ (to (org-wl-message-field 'to wl-message-entity))
+ (xref (org-wl-message-field 'xref wl-message-entity))
+ (subject (org-wl-message-field 'subject wl-message-entity))
+ (date (org-wl-message-field 'date wl-message-entity))
+ (date-ts (and date (format-time-string
+ (org-time-stamp-format t)
+ (date-to-time date))))
+ (date-ts-ia (and date (format-time-string
+ (org-time-stamp-format t t)
+ (date-to-time date))))
+ desc link)
+
+ ;; remove text properties of subject string to avoid possible bug
+ ;; when formatting the subject
+ ;; (Emacs bug #5306, fixed)
+ (set-text-properties 0 (length subject) nil subject)
+
+ ;; maybe remove filter condition
+ (when (and (eq folder-type 'filter) org-wl-link-remove-filter)
+ (while (eq (org-wl-folder-type folder-name) 'filter)
+ (setq folder-name
+ (replace-regexp-in-string "^/[^/]+/" "" folder-name))))
+
+ ;; maybe create http link
+ (cond
+ ((and (eq folder-type 'shimbun)
+ org-wl-shimbun-prefer-web-links xref)
+ (org-store-link-props :type "http" :link xref :description subject
+ :from from :to to :message-id message-id
+ :message-id-no-brackets message-id-no-brackets
+ :subject subject))
+ ((and (eq folder-type 'nntp) org-wl-nntp-prefer-web-links)
+ (setq link
+ (format
+ (if (string-match "gmane\\." folder-name)
+ "http://mid.gmane.org/%s"
+ "http://groups.google.com/groups/search?as_umsgid=%s")
+ (org-fixup-message-id-for-http message-id)))
+ (org-store-link-props :type "http" :link link :description subject
+ :from from :to to :message-id message-id
+ :message-id-no-brackets message-id-no-brackets
+ :subject subject))
+ (t
+ (org-store-link-props :type "wl" :from from :to to
+ :subject subject :message-id message-id
+ :message-id-no-brackets message-id-no-brackets)
+ (setq desc (org-email-link-description))
+ (setq link (concat "wl:" folder-name "#" message-id-no-brackets))
+ (org-add-link-props :link link :description desc)))
+ (when date
+ (org-add-link-props :date date :date-timestamp date-ts
+ :date-timestamp-inactive date-ts-ia))
+ (or link xref)))))))
+
+(defun org-wl-open-nntp (path)
+ "Follow the nntp: link specified by PATH."
+ (let* ((spec (split-string path "/"))
+ (server (split-string (nth 2 spec) "@"))
+ (group (nth 3 spec))
+ (article (nth 4 spec)))
+ (org-wl-open
+ (concat "-" group ":" (if (cdr server)
+ (car (split-string (car server) ":"))
+ "")
+ (if (string= elmo-nntp-default-server (nth 2 spec))
+ ""
+ (concat "@" (or (cdr server) (car server))))
+ (if article (concat "#" article) "")))))
+
+(defun org-wl-open (path)
+ "Follow the WL message link specified by PATH.
+When called with one prefix, open message in namazu search folder
+with `org-wl-namazu-default-index' as search index. When called
+with two prefixes or `org-wl-namazu-default-index' is nil, ask
+for namazu index."
+ (require 'wl)
+ (let ((wl-auto-check-folder-name
+ (if org-wl-disable-folder-check
+ 'none
+ wl-auto-check-folder-name)))
+ (unless wl-init (wl))
+ ;; XXX: The imap-uw's MH folder names start with "%#".
+ (if (not (string-match "\\`\\(\\(?:%#\\)?[^#]+\\)\\(#\\(.*\\)\\)?" path))
+ (error "Error in Wanderlust link"))
+ (let ((folder (match-string 1 path))
+ (article (match-string 3 path)))
+ ;; maybe open message in namazu search folder
+ (when current-prefix-arg
+ (setq folder (concat "[" article "]"
+ (if (and (equal current-prefix-arg '(4))
+ org-wl-namazu-default-index)
+ org-wl-namazu-default-index
+ (read-directory-name "Namazu index: ")))))
+ (if (not (elmo-folder-exists-p (org-no-warnings
+ (wl-folder-get-elmo-folder folder))))
+ (error "No such folder: %s" folder))
+ (let ((old-buf (current-buffer))
+ (old-point (point-marker)))
+ (wl-folder-goto-folder-subr folder)
+ (with-current-buffer old-buf
+ ;; XXX: `wl-folder-goto-folder-subr' moves point to the
+ ;; beginning of the current line. So, restore the point
+ ;; in the old buffer.
+ (goto-char old-point))
+ (when article
+ (if (org-string-match-p "@" article)
+ (wl-summary-jump-to-msg-by-message-id (org-add-angle-brackets
+ article))
+ (or (wl-summary-jump-to-msg (string-to-number article))
+ (error "No such message: %s" article)))
+ (wl-summary-redisplay))))))
+
+(provide 'org-wl)
+
+;;; org-wl.el ends here
diff --git a/contrib/lisp/org2rem.el b/contrib/lisp/org2rem.el
deleted file mode 100644
index 3052462..0000000
--- a/contrib/lisp/org2rem.el
+++ /dev/null
@@ -1,651 +0,0 @@
-;;; org2rem.el --- Convert org appointments into reminders
-
-;; Copyright (C) 2006-2012 Free Software Foundation, Inc.
-
-;; Author: Bastien Guerry and Shatad Pratap
-;; Keywords: outlines, hypermedia, calendar, wp
-;; Homepage: http://orgmode.org
-;; Version: 6.09a
-;;
-;; This file is not part of GNU Emacs.
-;;
-;; GNU Emacs 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.
-
-;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;;; Commentary:
-
-;; (require 'org2rem)
-;; To export, do
-;;
-;; M-x org2rem-combine-agenda-files
-;;
-;; Then you can use reming like this:
-;;
-;; $ remind ~/org.rem
-;;
-;; If you want to use this regualrly, try in .emacs
-;;
-;; (add-hook 'org-mode-hook
-;; (lambda() (add-hook 'after-save-hook
-;; 'org-export-remind-all-agenda-files t t)))
-
-(require 'org)
-(require 'org-agenda)
-(require 'org-exp)
-(eval-and-compile
- (require 'cl))
-
-(defgroup org2rem nil
- "Options specific for Remind export of Org-mode files."
- :tag "Org Export Remind"
- :group 'org-export)
-
-(defcustom org-combined-agenda-remind-file "~/org.rem"
- "The file name for the Remind file covering all agenda files.
-This file is created with the command \\[org2rem-all-agenda-files].
-The file name should be absolute, the file will be overwritten without warning."
- :group 'org2rem
- :type 'file)
-
-(defcustom org-remind-combined-name "OrgMode"
- "Calendar name for the combined Remind representing all agenda files."
- :group 'org2rem
- :type 'string)
-
-(defcustom org-remind-use-deadline '(event-if-not-todo todo-due)
- "Contexts where Remind export should use a deadline time stamp.
-This is a list with several symbols in it. Valid symbol are:
-
-event-if-todo Deadlines in TODO entries become calendar events.
-event-if-not-todo Deadlines in non-TODO entries become calendar events.
-todo-due Use deadlines in TODO entries as due-dates"
- :group 'org2rem
- :type '(set :greedy t
- (const :tag "Deadlines in non-TODO entries become events"
- event-if-not-todo)
- (const :tag "Deadline in TODO entries become events"
- event-if-todo)
- (const :tag "Deadlines in TODO entries become due-dates"
- todo-due)))
-
-(defcustom org-remind-use-scheduled '(todo-start)
- "Contexts where Remind export should use a scheduling time stamp.
-This is a list with several symbols in it. Valid symbol are:
-
-event-if-todo Scheduling time stamps in TODO entries become an event.
-event-if-not-todo Scheduling time stamps in non-TODO entries become an event.
-todo-start Scheduling time stamps in TODO entries become start date.
- Some calendar applications show TODO entries only after
- that date."
- :group 'org2rem
- :type '(set :greedy t
- (const :tag
- "SCHEDULED timestamps in non-TODO entries become events"
- event-if-not-todo)
- (const :tag "SCHEDULED timestamps in TODO entries become events"
- event-if-todo)
- (const :tag "SCHEDULED in TODO entries become start date"
- todo-start)))
-
-(defcustom org-remind-categories '(local-tags category)
- "Items that should be entered into the categories field.
-This is a list of symbols, the following are valid:
-
-category The Org-mode category of the current file or tree
-todo-state The todo state, if any
-local-tags The tags, defined in the current line
-all-tags All tags, including inherited ones."
- :group 'org2rem
- :type '(repeat
- (choice
- (const :tag "The file or tree category" category)
- (const :tag "The TODO state" todo-state)
- (const :tag "Tags defined in current line" local-tags)
- (const :tag "All tags, including inherited ones" all-tags))))
-
-(defcustom org-remind-include-todo nil
- "Non-nil means export to remind files should also cover TODO items."
- :group 'org2rem
- :type '(choice
- (const :tag "None" nil)
- (const :tag "Unfinished" t)
- (const :tag "All" all)))
-
-(defcustom org-remind-include-sexps t
- "Non-nil means export to Remind files should also cover sexp entries.
-These are entries like in the diary, but directly in an Org-mode file."
- :group 'org2rem
- :type 'boolean)
-
-(defcustom org-remind-deadline-over-scheduled t
- "Non-nil means use deadline as target when both deadline and
-scheduled present, vice-versa. Default is Non-nil."
- :group 'org2rem
- :type 'boolean)
-
-(defcustom org-remind-escape-percentage t
- "Non-nil means % will be escaped, vice-versa. Default is Non-nil."
- :group 'org2rem
- :type 'boolean)
-
-(defcustom org-remind-extra-warn-days 3
- "Extra days Remind keep reminding."
- :group 'org2rem
- :type 'number)
-
-(defcustom org-remind-advanced-warn-days 3
- "Advanced days Remind start reminding."
- :group 'org2rem
- :type 'number)
-
-(defcustom org-remind-suppress-last-newline nil
- "Non-nil means suppress last newline REM body. Default is nil."
- :group 'org2rem
- :type 'boolean)
-
-(defcustom org-remind-include-body 100
- "Amount of text below headline to be included in Remind export.
-This is a number of characters that should maximally be included.
-Properties, scheduling and clocking lines will always be removed.
-The text will be inserted into the DESCRIPTION field."
- :group 'org2rem
- :type '(choice
- (const :tag "Nothing" nil)
- (const :tag "Everything" t)
- (integer :tag "Max characters")))
-
-(defcustom org-remind-store-UID nil
- "Non-nil means store any created UIDs in properties.
-The Remind standard requires that all entries have a unique identifyer.
-Org will create these identifiers as needed. When this variable is non-nil,
-the created UIDs will be stored in the ID property of the entry. Then the
-next time this entry is exported, it will be exported with the same UID,
-superceeding the previous form of it. This is essential for
-synchronization services.
-This variable is not turned on by default because we want to avoid creating
-a property drawer in every entry if people are only playing with this feature,
-or if they are only using it locally."
- :group 'org2rem
- :type 'boolean)
-
-;;;; Exporting
-
-;;; Remind export
-
-;;;###autoload
-(defun org2rem-this-file ()
- "Export current file as an Remind file.
-The Remind file will be located in the same directory as the Org-mode
-file, but with extension `.rem'."
- (interactive)
- (org2rem nil buffer-file-name))
-
-;;;###autoload
-(defun org2rem-all-agenda-files ()
- "Export all files in `org-agenda-files' to Remind .rem files.
-Each Remind file will be located in the same directory as the Org-mode
-file, but with extension `.rem'."
- (interactive)
- (apply 'org2rem nil (org-agenda-files t)))
-
-;;;###autoload
-(defun org2rem-combine-agenda-files ()
- "Export all files in `org-agenda-files' to a single combined Remind file.
-The file is stored under the name `org-combined-agenda-remind-file'."
- (interactive)
- (apply 'org2rem t (org-agenda-files t)))
-
-(defun org2rem (combine &rest files)
- "Create Remind files for all elements of FILES.
-If COMBINE is non-nil, combine all calendar entries into a single large
-file and store it under the name `org-combined-agenda-remind-file'."
- (save-excursion
- (org-agenda-prepare-buffers files)
- (let* ((dir (org-export-directory
- :ical (list :publishing-directory
- org-export-publishing-directory)))
- file rem-file rem-buffer category started org-agenda-new-buffers)
- (and (get-buffer "*rem-tmp*") (kill-buffer "*rem-tmp*"))
- (when combine
- (setq rem-file
- (if (file-name-absolute-p org-combined-agenda-remind-file)
- org-combined-agenda-remind-file
- (expand-file-name org-combined-agenda-remind-file dir))
- rem-buffer (org-get-agenda-file-buffer rem-file))
- (set-buffer rem-buffer) (erase-buffer))
- (while (setq file (pop files))
- (catch 'nextfile
- (org-check-agenda-file file)
- (set-buffer (org-get-agenda-file-buffer file))
- (unless combine
- (setq rem-file (concat (file-name-as-directory dir)
- (file-name-sans-extension
- (file-name-nondirectory buffer-file-name))
- ".rem"))
- (setq rem-buffer (org-get-agenda-file-buffer rem-file))
- (with-current-buffer rem-buffer (erase-buffer)))
- (setq category (or org-category
- (file-name-sans-extension
- (file-name-nondirectory buffer-file-name))))
- (if (symbolp category) (setq category (symbol-name category)))
- (let ((standard-output rem-buffer))
- (if combine
- (and (not started) (setq started t)
- (org-start-remind-file org-remind-combined-name))
- (org-start-remind-file category))
- (org-print-remind-entries combine)
- (when (or (and combine (not files)) (not combine))
- (org-finish-remind-file)
- (set-buffer rem-buffer)
- (run-hooks 'org-before-save-Remind-file-hook)
- (save-buffer)
- (run-hooks 'org-after-save-Remind-file-hook)
- (and (boundp 'org-wait) (numberp org-wait) (sit-for org-wait))
- ))))
- (org-release-buffers org-agenda-new-buffers))))
-
-(defvar org-before-save-Remind-file-hook nil
- "Hook run before an Remind file has been saved.
-This can be used to modify the result of the export.")
-
-(defvar org-after-save-Remind-file-hook nil
- "Hook run after an Remind file has been saved.
-The Remind buffer is still current when this hook is run.
-A good way to use this is to tell a desktop calenndar application to re-read
-the Remind file.")
-
-(defvar org-agenda-default-appointment-duration) ; defined in org-agenda.el
-(defun org-print-remind-entries (&optional combine)
- "Print Remind entries for the current Org-mode file to `standard-output'.
-When COMBINE is non nil, add the category to each line."
- (require 'org-agenda)
- (let ((re1 (concat org-ts-regexp "\\|<%%([^>\n]+>"))
- (re2 (concat "--?-?\\(" org-ts-regexp "\\)"))
- (dts (org-rem-ts-to-string
- (format-time-string (cdr org-time-stamp-formats) (current-time))
- "start time:"))
- hd ts ts2 state status (inc t) pos b sexp rrule
- scheduledp deadlinep todo prefix due start
- tmp pri categories entry location summary desc uid
- remind-aw remind-ew (org-rem-ew org-remind-extra-warn-days)
- (org-rem-aw org-remind-advanced-warn-days)
- trigger diff-days (dos org-remind-deadline-over-scheduled)
- (suppress-last-newline org-remind-suppress-last-newline)
- (sexp-buffer (get-buffer-create "*rem-tmp*")))
- (org-refresh-category-properties)
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward re1 nil t)
- (catch :skip
- (org-agenda-skip)
- (when (boundp 'org-remind-verify-function)
- (unless (funcall org-remind-verify-function)
- (outline-next-heading)
- (backward-char 1)
- (throw :skip nil)))
- (setq pos (match-beginning 0)
- ts (match-string 0)
- inc t
- hd (condition-case nil
- (org-remind-cleanup-string
- (org-get-heading))
- (error (throw :skip nil)))
- summary (org-remind-cleanup-string
- (org-entry-get nil "SUMMARY"))
- desc (org-remind-cleanup-string
- (or (org-entry-get nil "DESCRIPTION")
- (and org-remind-include-body (org-get-entry)))
- t org-remind-include-body)
- location (org-remind-cleanup-string
- (org-entry-get nil "LOCATION"))
- uid (if org-remind-store-UID
- (org-id-get-create)
- (or (org-id-get) (org-id-new)))
- categories (org-export-get-remind-categories)
- deadlinep nil scheduledp nil)
- (if (looking-at re2)
- (progn
- (goto-char (match-end 0))
- (setq ts2 (match-string 1)
- inc (not (string-match "[0-9]\\{1,2\\}:[0-9][0-9]" ts2))))
- (setq tmp (buffer-substring (max (point-min)
- (- pos org-ds-keyword-length))
- pos)
- ts2 (if (string-match "[0-9]\\{1,2\\}:[0-9][0-9]-\\([0-9]\\{1,2\\}:[0-9][0-9]\\)" ts)
- (progn
- (setq inc nil)
- (replace-match "\\1" t nil ts))
- ts)
- deadlinep (string-match org-deadline-regexp tmp)
- scheduledp (string-match org-scheduled-regexp tmp)
- todo (org-get-todo-state)
- ;; donep (org-entry-is-done-p)
- ))
- (when (and
- deadlinep
- (if todo
- (not (memq 'event-if-todo org-remind-use-deadline))
- (not (memq 'event-if-not-todo org-remind-use-deadline))))
- (throw :skip t))
- (when (and
- scheduledp
- (if todo
- (not (memq 'event-if-todo org-remind-use-scheduled))
- (not (memq 'event-if-not-todo org-remind-use-scheduled))))
- (throw :skip t))
- (setq prefix (if deadlinep "DEADLINE-" (if scheduledp "SCHEDULED-" "TS-")))
- (if (or (string-match org-tr-regexp hd)
- (string-match org-ts-regexp hd))
- (setq hd (replace-match "" t t hd)))
- (if (string-match "\\+\\([0-9]+\\)\\([dwmy]\\)>" ts)
- (setq rrule ;is recurrence value. later give it good name.
- (* (string-to-number
- (cdr (assoc
- (match-string 2 ts)
- '(("d" . "1")("w" . "7")
- ("m" . "0")("y" . "0")))))
- (string-to-number (match-string 1 ts))))
- (setq rrule nil))
- (setq summary (or summary hd))
- (if (string-match org-bracket-link-regexp summary)
- (setq summary
- (replace-match (if (match-end 3)
- (match-string 3 summary)
- (match-string 1 summary))
- t t summary)))
- (if deadlinep (setq summary (concat "DEADLINE: " summary)))
- (if scheduledp (setq summary (concat "SCHEDULED: " summary)))
- (if (string-match "\\`<%%" ts)
- (with-current-buffer sexp-buffer
- (insert (substring ts 1 -1) " " summary "\n"))
- (princ (format "\n## BEGIN:EVENT
-## UID: %s
-REM %s %s MSG EVENT:%s%s %s%s%%
-## CATEGORIES:%s
-## END:EVENT\n"
- (concat prefix uid)
- (org-rem-ts-to-string ts nil nil rrule)
- (org-rem-ts-to-string ts2 "UNTIL " inc)
- summary
- (if (and desc (string-match "\\S-" desc))
- (concat "%_\\\n" desc) "")
- (if (and location (string-match "\\S-" location))
- (concat "\nLOCATION: " location) "")
- (if suppress-last-newline "" "%_")
- categories)))))
-
- (when (and org-remind-include-sexps
- (condition-case nil (require 'remind) (error nil))
- (fboundp 'remind-export-region))
- ;; Get all the literal sexps
- (goto-char (point-min))
- (while (re-search-forward "^&?%%(" nil t)
- (catch :skip
- (org-agenda-skip)
- (setq b (match-beginning 0))
- (goto-char (1- (match-end 0)))
- (forward-sexp 1)
- (end-of-line 1)
- (setq sexp (buffer-substring b (point)))
- (with-current-buffer sexp-buffer
- (insert sexp "\n"))))
- ;; (princ (org-diary-to-rem-string sexp-buffer))
- (kill-buffer sexp-buffer))
-
- (when org-remind-include-todo
- (setq prefix "TODO-")
- (goto-char (point-min))
- (while (re-search-forward org-todo-line-regexp nil t)
- (catch :skip
- (org-agenda-skip)
- (when (boundp 'org-remind-verify-function)
- (unless (funcall org-remind-verify-function)
- (outline-next-heading)
- (backward-char 1)
- (throw :skip nil)))
- (setq state (match-string 2))
- (setq status (if (member state org-done-keywords)
- "COMPLETED" "NEEDS-ACTION"))
- (when (and state
- (or (not (member state org-done-keywords))
- (eq org-remind-include-todo 'all))
- (not (member org-archive-tag (org-get-tags-at)))
- )
- (setq hd (match-string 3)
- summary (org-remind-cleanup-string
- (org-entry-get nil "SUMMARY"))
- desc (org-remind-cleanup-string
- (or (org-entry-get nil "DESCRIPTION")
- (and org-remind-include-body (org-get-entry)))
- t org-remind-include-body)
- location (org-remind-cleanup-string
- (org-entry-get nil "LOCATION"))
- due (and (member 'todo-due org-remind-use-deadline)
- (org-entry-get nil "DEADLINE"))
- start (and (member 'todo-start org-remind-use-scheduled)
- (org-entry-get nil "SCHEDULED"))
- categories (org-export-get-remind-categories)
- uid (if org-remind-store-UID
- (org-id-get-create)
- (or (org-id-get) (org-id-new))))
-
- (if (and due start)
- (setq diff-days (org-rem-time-diff-days due start)))
-
- (setq remind-aw
- (if due
- (if diff-days
- (if (> diff-days 0)
- (if dos diff-days 0)
- (if dos 0 diff-days))
- 1000)))
-
- (if (and (numberp org-rem-aw) (> org-rem-aw 0))
- (setq remind-aw (+ (or remind-aw 0) org-rem-aw)))
-
- (setq remind-ew
- (if due
- (if diff-days
- (if (> diff-days 0) due nil)
- due)))
-
- (setq trigger (if dos (if due due start) (if start start due)))
- ;; (and trigger (setq trigger (org-rem-ts-to-string trigger nil nil 1 remind-aw)))
- (if trigger
- (setq trigger (concat
- (format "[trigger('%s')] *%d "
- (org-rem-ts-to-remind-date-type trigger) 1)
- (if remind-aw (format "++%d" remind-aw)))))
- (and due (setq due (org-rem-ts-to-remind-date-type due)))
- (and start (setq start (org-rem-ts-to-remind-date-type start)))
- (and remind-ew (setq remind-ew (org-rem-ts-to-remind-date-type remind-ew)))
-
- (if (string-match org-bracket-link-regexp hd)
- (setq hd (replace-match (if (match-end 3) (match-string 3 hd)
- (match-string 1 hd))
- t t hd)))
- (if (string-match org-priority-regexp hd)
- (setq pri (string-to-char (match-string 2 hd))
- hd (concat (substring hd 0 (match-beginning 1))
- (substring hd (match-end 1))))
- (setq pri org-default-priority))
- (setq pri (floor (1+ (* 8. (/ (float (- org-lowest-priority pri))
- (- org-lowest-priority org-highest-priority))))))
-
- (princ (format "\n## BEGIN:TODO
-## UID: %s
-REM %s %s %s MSG TODO: %s%s%s%s%s%s%%
-## CATEGORIES:%s
-## SEQUENCE:1
-## STATUS:%s
-## END:TODO\n"
- (concat prefix uid)
- (or trigger "") ;; dts)
- (if remind-ew (format "UNTIL [trigger('%s' + %d)]" remind-ew (or org-rem-ew 0)) "")
- (if pri (format "PRIORITY %d" pri) "")
- (or summary hd)
- (if (and desc (string-match "\\S-" desc))
- (concat "%_\\\nDESCRIPTION: " desc) "")
- (if (and location (string-match "\\S-" location))
- (concat "LOCATION: " location) "")
- (if start
- (concat
- "%_\\\n['" start "' - today()] "
- "days over, for scheduled date - "
- "[trigger('" start "')]") "")
- (if due
- (concat
- "%_\\\n[today() - '" due "'] "
- "days left, to deadline date - "
- "[trigger('" due "')]") "")
- (if suppress-last-newline "" "%_")
- categories
- status)))))))))
-
-(defun org-export-get-remind-categories ()
- "Get categories according to `org-remind-categories'."
- (let ((cs org-remind-categories) c rtn tmp)
- (while (setq c (pop cs))
- (cond
- ((eq c 'category) (push (org-get-category) rtn))
- ((eq c 'todo-state)
- (setq tmp (org-get-todo-state))
- (and tmp (push tmp rtn)))
- ((eq c 'local-tags)
- (setq rtn (append (nreverse (org-get-local-tags-at (point))) rtn)))
- ((eq c 'all-tags)
- (setq rtn (append (nreverse (org-get-tags-at (point))) rtn)))))
- (mapconcat 'identity (nreverse rtn) ",")))
-
-(defun org-remind-cleanup-string (s &optional is-body maxlength)
- "Take out stuff and quote what needs to be quoted.
-When IS-BODY is non-nil, assume that this is the body of an item, clean up
-whitespace, newlines, drawers, and timestamps, and cut it down to MAXLENGTH
-characters."
- (if (or (not s) (string-match "^[ \t\n]*$" s))
- nil
- (when is-body
- (let ((re (concat "\\(" org-drawer-regexp "\\)[^\000]*?:END:.*\n?"))
- (re2 (concat "^[ \t]*" org-keyword-time-regexp ".*\n?")))
- (while (string-match re s) (setq s (replace-match "" t t s)))
- (while (string-match re2 s) (setq s (replace-match "" t t s)))))
- (if org-remind-escape-percentage
- (let ((start 0))
- (while (string-match "\\([%]\\)" s start)
- (setq start (+ (match-beginning 0) 2)
- s (replace-match "\\1\\1" nil nil s)))))
-
- (let ((start 0))
- (while (string-match "\\([\n]\\)" s start)
- (setq start (+ (match-beginning 0) 4) ;; less than 4 is not correct.
- s (replace-match "%_\\\\\\1" nil nil s))))
-
- (let ((start 0))
- (while (string-match "\\([[]\\)" s start)
- (setq start (+ (match-beginning 0) 5)
- s (replace-match (concat "\[" "\"" "\\1" "\"" "\]") nil nil s))))
-
-;;; (when is-body
-;;; (while (string-match "[ \t]*\n[ \t]*" s)
-;;; (setq s (replace-match "%_" t t s))))
-
- (setq s (org-trim s))
- (if is-body
- (if maxlength
- (if (and (numberp maxlength)
- (> (length s) maxlength))
- (setq s (substring s 0 maxlength)))))
- s))
-
-(defun org-get-entry ()
- "Clean-up description string."
- (save-excursion
- (org-back-to-heading t)
- (buffer-substring (point-at-bol 2) (org-end-of-subtree t))))
-
-(defun org-start-remind-file (name)
- "Start an Remind file by inserting the header."
- (let ((user user-full-name)
- (name (or name "unknown"))
- (timezone (cadr (current-time-zone))))
- (princ
- (format "# -*- Mode: shell-script; auto-fill-mode: nil -*-
-## BEGIN: Reminders
-## VERSION:2.0
-## Emacs with Org-mode
-## Calendar:%s
-## Created by: %s
-## Timezone:%s
-## Calscale:Gregorian\n" name user timezone))))
-
-(defun org-finish-remind-file ()
- "Finish an Remind file by inserting the END statement."
- (princ "\n## END:Reminders\n"))
-
-(defun org-rem-ts-to-remind-date-type (s)
- (format-time-string
- "%Y-%m-%d"
- (apply 'encode-time (butlast (org-parse-time-string s) 3))))
-
-;; (defun org-rem-date-type-to-string (s keyword &optional inc day-repeat day-advance-warn)
-;; (if trigger
-;; (setq trigger
-;; (concat
-;; (format "[trigger('%s')] *%d "
-;; (org-rem-ts-to-remind-date-type trigger) day-repeat)
-;; (if day-advance-warn (format "++%d" day-advance-warn))))))
-
-;; (format-time-string "%Y"
-;; (apply 'encode-time (butlast (org-parse-time-string "<2008-11-20 Thu 10:30>") 3)))
-
-(defun org-rem-ts-to-string (s keyword &optional inc day-repeat day-advance-warn)
- "Take a time string S and convert it to Remind format.
-KEYWORD is added in front, to make a complete line like DTSTART....
-When INC is non-nil, increase the hour by two (if time string contains
-a time), or the day by one (if it does not contain a time)."
- (let ((t1 (org-parse-time-string s 'nodefault))
- t2 fmt have-time time)
- (if (and (car t1) (nth 1 t1) (nth 2 t1))
- (setq t2 t1 have-time t)
- (setq t2 (org-parse-time-string s)))
- (let ((s (car t2)) (mi (nth 1 t2)) (h (nth 2 t2))
- (d (nth 3 t2)) (m (nth 4 t2)) (y (nth 5 t2)))
- (when inc
- (if have-time
- (if org-agenda-default-appointment-duration
- (setq mi (+ org-agenda-default-appointment-duration mi))
- (setq h (+ 2 h)))
- (setq d (1+ d))))
- (setq time (encode-time s mi h d m y)))
- (setq fmt (concat
- "%d %b %Y"
- (if day-advance-warn (format " ++%d" day-advance-warn))
- (if day-repeat (format " *%d" day-repeat))
- (if have-time " AT %H:%M")))
- (concat keyword (format-time-string fmt time))))
-
-(defun org-rem-time-diff-days (end start)
- (floor (/ (apply '- (mapcar
- (lambda (s)
- (let*
- ((t1 (org-parse-time-string s))
- (s (car t1)) (mi (nth 1 t1))
- (h (nth 2 t1)) (d (nth 3 t1))
- (m (nth 4 t1)) (y (nth 5 t1)))
- (float-time (encode-time s mi h d m y))))
- (list end start))) (* 24 60 60))))
-
-(provide 'org2rem)
-
-;;; org-exp.el ends here
diff --git a/contrib/lisp/orgtbl-sqlinsert.el b/contrib/lisp/orgtbl-sqlinsert.el
index d2580d8..b00c93d 100644
--- a/contrib/lisp/orgtbl-sqlinsert.el
+++ b/contrib/lisp/orgtbl-sqlinsert.el
@@ -1,10 +1,12 @@
;;; orgtbl-sqlinsert.el --- orgtbl to SQL insert statements.
-;; Copyright (C) 2008-2012 Free Software Foundation
+;; Copyright (C) 2008-2013 Free Software Foundation
;; Author: Jason Riedy <jason@acm.org>
;; Keywords: org, tables, sql
+;; This file is not part of GNU Emacs.
+
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
@@ -68,14 +70,14 @@ this function is called."
(*orgtbl-default-fmt* 'orgtbl-sql-strip-and-quote)
(params2
(list
- :sqlname name
+ :sqlname (plist-get params :sqlname)
:tstart (lambda () (concat (if nowebname
(format "<<%s>>= \n" nowebname)
"")
"BEGIN TRANSACTION;"))
:tend (lambda () (concat "COMMIT;" (if nowebname "\n@ " "")))
- :hfmt (lambda (f) (progn (if firstheader (push f hdrlist)) ""))
- :hlfmt (lambda (lst) (setq firstheader nil))
+ :hfmt (lambda (f) (progn (if firstheader (push f hdrlist) "")))
+ :hlfmt (lambda (&rest cells) (setq firstheader nil))
:lstart (lambda () (concat "INSERT INTO "
sqlname "( "
(mapconcat 'identity (reverse hdrlist)
diff --git a/contrib/lisp/ox-confluence.el b/contrib/lisp/ox-confluence.el
new file mode 100644
index 0000000..5e01e1e
--- /dev/null
+++ b/contrib/lisp/ox-confluence.el
@@ -0,0 +1,191 @@
+;;; ox-confluence --- Confluence Wiki Back-End for Org Export Engine
+
+;; Copyright (C) 2012 Sébastien Delafond
+
+;; Author: Sébastien Delafond <sdelafond at gmx dot net>
+;; Keywords: outlines, confluence, wiki
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; ox-confluence.el lets you convert Org files to confluence files
+;; using the ox.el export engine.
+;;
+;; Put this file into your load-path and the following into your ~/.emacs:
+;; (require 'ox-confluence)
+;;
+;; Export Org files to confluence:
+;; M-x org-confluence-export-as-confluence RET
+;;
+;;; Code:
+
+(require 'ox)
+(require 'ox-ascii)
+
+;; Define the backend itself
+(org-export-define-derived-backend 'confluence 'ascii
+ :translate-alist '((bold . org-confluence-bold)
+ (example-block . org-confluence-example-block)
+ (fixed-width . org-confluence-fixed-width)
+ (footnote-definition . org-confluence-empty)
+ (footnote-reference . org-confluence-empty)
+ (headline . org-confluence-headline)
+ (italic . org-confluence-italic)
+ (link . org-confluence-link)
+ (section . org-confluence-section)
+ (src-block . org-confluence-src-block)
+ (strike-through . org-confluence-strike-through)
+ (table . org-confluence-table)
+ (table-cell . org-confluence-table-cell)
+ (table-row . org-confluence-table-row)
+ (template . org-confluence-template)
+ (underline . org-confluence-underline)))
+
+;; All the functions we use
+(defun org-confluence-bold (bold contents info)
+ (format "*%s*" contents))
+
+(defun org-confluence-empty (empty contents info)
+ "")
+
+(defun org-confluence-example-block (example-block contents info)
+ ;; FIXME: provide a user-controlled variable for theme
+ (let ((content (org-export-format-code-default example-block info)))
+ (org-confluence--block "none" "Confluence" content)))
+
+(defun org-confluence-italic (italic contents info)
+ (format "_%s_" contents))
+
+(defun org-confluence-fixed-width (fixed-width contents info)
+ (format "\{\{%s\}\}" contents))
+
+(defun org-confluence-headline (headline contents info)
+ (let ((low-level-rank (org-export-low-level-p headline info))
+ (text (org-export-data (org-element-property :title headline)
+ info))
+ (level (org-export-get-relative-level headline info)))
+ ;; Else: Standard headline.
+ (format "h%s. %s\n%s" level text
+ (if (org-string-nw-p contents) contents
+ ""))))
+
+(defun org-confluence-link (link desc info)
+ (let ((raw-link (org-element-property :raw-link link)))
+ (concat "["
+ (when (org-string-nw-p desc) (format "%s|" desc))
+ (cond
+ ((string-match "^confluence:" raw-link)
+ (replace-regexp-in-string "^confluence:" "" raw-link))
+ (t
+ raw-link))
+ "]")))
+(defun org-confluence-section (section contents info)
+ contents)
+
+(defun org-confluence-src-block (src-block contents info)
+ ;; FIXME: provide a user-controlled variable for theme
+ (let* ((lang (org-element-property :language src-block))
+ (language (if (string= lang "sh") "bash" ;; FIXME: provide a mapping of some sort
+ lang))
+ (content (org-export-format-code-default src-block info)))
+ (org-confluence--block language "Emacs" content)))
+
+(defun org-confluence-strike-through (strike-through contents info)
+ (format "-%s-" contents))
+
+(defun org-confluence-table (table contents info)
+ contents)
+
+(defun org-confluence-table-row (table-row contents info)
+ (concat
+ (if (org-string-nw-p contents) (format "|%s" contents)
+ "")
+ (when (org-export-table-row-ends-header-p table-row info)
+ "|")))
+
+(defun org-confluence-table-cell (table-cell contents info)
+ (let ((table-row (org-export-get-parent table-cell)))
+ (concat
+ (when (org-export-table-row-starts-header-p table-row info)
+ "|")
+ contents "|")))
+
+(defun org-confluence-template (contents info)
+ (let ((depth (plist-get info :with-toc)))
+ (concat (when depth "\{toc\}\n\n") contents)))
+
+(defun org-confluence-underline (underline contents info)
+ (format "+%s+" contents))
+
+(defun org-confluence--block (language theme contents)
+ (concat "\{code:theme=" theme
+ (when language (format "|language=%s" language))
+ "}\n"
+ contents
+ "\{code\}\n"))
+
+;; main interactive entrypoint
+(defun org-confluence-export-as-confluence
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to a text buffer.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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, strip title, table
+of contents and footnote definitions from output.
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Export is done in a buffer named \"*Org E-Confluence Export*\", which
+will be displayed when `org-export-show-temporary-export-buffer'
+is non-nil."
+ (interactive)
+ (if async
+ (org-export-async-start
+ (lambda (output)
+ (with-current-buffer (get-buffer-create "*Org E-Confluence Export*")
+ (erase-buffer)
+ (insert output)
+ (goto-char (point-min))
+ (text-mode)
+ (org-export-add-to-stack (current-buffer) 'confluence)))
+ `(org-export-as 'confluence ,subtreep ,visible-only ,body-only
+ ',ext-plist))
+ (let ((outbuf (org-export-to-buffer
+ 'confluence "*Org E-Confluence Export*"
+ subtreep visible-only body-only ext-plist)))
+ (with-current-buffer outbuf (text-mode))
+ (when org-export-show-temporary-export-buffer
+ (switch-to-buffer-other-window outbuf)))))
+
+(provide 'ox-confluence)
diff --git a/contrib/lisp/ox-deck.el b/contrib/lisp/ox-deck.el
new file mode 100644
index 0000000..c738389
--- /dev/null
+++ b/contrib/lisp/ox-deck.el
@@ -0,0 +1,601 @@
+;;; ox-deck.el --- deck.js Presentation Back-End for Org Export Engine
+
+;; Copyright (C) 2013 Rick Frankel
+
+;; Author: Rick Frankel <emacs at rickster dot com>
+;; Keywords: outlines, hypermedia, slideshow
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library implements a deck.js presentation back-end for the Org
+;; generic exporter.
+
+;; Installation
+;; -------------
+;; Get a copy of deck.js from http://imakewebthings.com/deck.js/ or
+;; the gitub repository at https://github.com/imakewebthings/deck.js.
+;;
+;; Add the path to the extracted code to the variable
+;; `org-deck-directories' There are a number of customization in the
+;; org-export-deck group, most of which can be overrriden with buffer
+;; local customization (starting with DECK_.)
+
+;; See ox.el and ox-html.el for more details on how this exporter
+;; works (it is derived from ox-html.)
+
+(require 'ox-html)
+(eval-when-compile (require 'cl))
+
+(org-export-define-derived-backend 'deck 'html
+ :menu-entry
+ '(?d "Export to deck.js HTML Presentation"
+ ((?H "To temporary buffer" org-deck-export-as-html)
+ (?h "To file" org-deck-export-to-html)
+ (?o "To file and open"
+ (lambda (a s v b)
+ (if a (org-deck-export-to-html t s v b)
+ (org-open-file (org-deck-export-to-html nil s v b)))))))
+ :options-alist
+ '((:html-link-home "HTML_LINK_HOME" nil nil)
+ (:html-link-up "HTML_LINK_UP" nil nil)
+ (:deck-postamble "DECK_POSTAMBLE" nil org-deck-postamble newline)
+ (:deck-preamble "DECK_PREAMBLE" nil org-deck-preamble newline)
+ (:html-head-include-default-style "HTML_INCLUDE_DEFAULT_STYLE" nil nil)
+ (:html-head-include-scripts "HTML_INCLUDE_SCRIPTS" nil nil)
+ (:deck-base-url "DECK_BASE_URL" nil org-deck-base-url)
+ (:deck-theme "DECK_THEME" nil org-deck-theme)
+ (:deck-transition "DECK_TRANSITION" nil org-deck-transition)
+ (:deck-include-extensions "DECK_INCLUDE_EXTENSIONS" nil
+ org-deck-include-extensions split)
+ (:deck-exclude-extensions "DECK_EXCLUDE_EXTENSIONS" nil
+ org-deck-exclude-extensions split))
+ :translate-alist
+ '((headline . org-deck-headline)
+ (inner-template . org-deck-inner-template)
+ (item . org-deck-item)
+ (link . org-deck-link)
+ (template . org-deck-template)))
+
+(defgroup org-export-deck nil
+ "Options for exporting Org mode files to deck.js HTML Presentations."
+ :tag "Org Export DECK"
+ :group 'org-export-html)
+
+(defcustom org-deck-directories '("./deck.js")
+ "Directories to search for deck.js components (jquery,
+modernizr; core, extensions and themes directories.)"
+ :group 'org-export-deck
+ :type '(repeat (string :tag "Directory")))
+
+(defun org-deck--cleanup-components (components)
+ (remove-duplicates
+ (car (remove 'nil components))
+ :test (lambda (x y)
+ (string= (file-name-nondirectory x)
+ (file-name-nondirectory y)))))
+
+(defun org-deck--find-extensions ()
+ "Returns a unique list of all extensions found in
+in the extensions directories under `org-deck-directories'"
+ (org-deck--cleanup-components
+ (mapcar ; extensions under existing dirs
+ (lambda (dir)
+ (when (file-directory-p dir) (directory-files dir t "^[^.]")))
+ (mapcar ; possible extension directories
+ (lambda (x) (expand-file-name "extensions" x))
+ org-deck-directories))))
+
+(defun org-deck--find-css (type)
+ "Return a unique list of all the css stylesheets in the themes/TYPE
+directories under `org-deck-directories'."
+ (org-deck--cleanup-components
+ (mapcar
+ (lambda (dir)
+ (let ((css-dir (expand-file-name
+ (concat (file-name-as-directory "themes") type) dir)))
+ (when (file-directory-p css-dir)
+ (directory-files css-dir t "\\.css$"))))
+ org-deck-directories)))
+
+(defun org-deck-list-components ()
+ "List all available deck extensions, styles and
+transitions (with full paths) to a temporary buffer."
+ (interactive)
+ (let ((outbuf (get-buffer-create "*deck.js Extensions*")))
+ (with-current-buffer outbuf
+ (erase-buffer)
+ (insert "Extensions\n----------\n")
+ (insert (mapconcat 'identity (org-deck--find-extensions) "\n"))
+ (insert "\n\nStyles\n------\n")
+ (insert (mapconcat 'identity (org-deck--find-css "style") "\n"))
+ (insert "\n\nTransitions\n----------\n")
+ (insert (mapconcat 'identity (org-deck--find-css "transition") "\n")))
+ (switch-to-buffer-other-window outbuf)))
+
+(defcustom org-deck-include-extensions nil
+ "If non-nil, list of extensions to include instead of all available.
+Can be overriden or set with the DECK_INCLUDE_EXTENSIONS property.
+During output generation, the extensions found by
+`org-deck--find-extensions' are searched for the appropriate
+files (scripts and/or stylesheets) to include in the generated
+html. The href/src attributes are created relative to `org-deck-base-url'."
+ :group 'org-export-deck
+ :type '(repeat (string :tag "Extension")))
+
+(defcustom org-deck-exclude-extensions nil
+ "If non-nil, list of extensions to exclude.
+Can be overriden or set with the DECK_EXCLUDE_EXTENSIONS property."
+ :group 'org-export-deck
+ :type '(repeat (string :tag "Extension")))
+
+(defcustom org-deck-theme "swiss.css"
+ "deck.js theme. Can be overriden with the DECK_THEME property.
+If this value contains a path component (\"/\"), it is used as a
+literal path (url). Otherwise it is prepended with
+`org-deck-base-url'/themes/style/."
+ :group 'org-export-deck
+ :type 'string)
+
+(defcustom org-deck-transition "fade.css"
+ "deck.js transition theme. Can be overriden with the
+DECK_TRANSITION property.
+If this value contains a path component (\"/\"), it is used as a
+literal path (url). Otherwise it is prepended with
+`org-deck-base-url'/themes/transition/."
+ :group 'org-export-deck
+ :type 'string)
+
+(defcustom org-deck-base-url "deck.js"
+ "Url prefix to deck.js base directory containing the core, extensions
+and themes directories.
+Can be overriden with the DECK_BASE_URL property."
+ :group 'org-export-deck
+ :type 'string)
+
+(defvar org-deck-pre/postamble-styles
+ `((both "left: 5px; width: 100%;")
+ (preamble "position: absolute; top: 10px;")
+ (postamble ""))
+ "Alist of css styles for the preamble, postamble and both respectively.
+Can be overriden in `org-deck-styles'. See also `org-html-divs'.")
+
+(defcustom org-deck-postamble "<h1>%a - %t</h1>"
+ "Non-nil means insert a postamble in HTML export.
+
+When set to a string, use this string
+as the postamble. When t, insert a string as defined by the
+formatting string in `org-html-postamble-format'.
+
+When set to a function, apply this function and insert the
+returned string. The function takes the property list of export
+options as its only argument.
+
+This is included in the document at the bottom of the content
+section, and uses the postamble element and id from
+`org-html-divs'. The default places the author and presentation
+title at the bottom of each slide.
+
+The css styling is controlled by `org-deck-pre/postamble-styles'.
+
+Setting :deck-postamble in publishing projects will take
+precedence over this variable."
+ :group 'org-export-deck
+ :type '(choice (const :tag "No postamble" nil)
+ (const :tag "Default formatting string" t)
+ (string :tag "Custom formatting string")
+ (function :tag "Function (must return a string)")))
+
+(defcustom org-deck-preamble nil
+ "Non-nil means insert a preamble in HTML export.
+
+When set to a string, use this string
+as the preamble. When t, insert a string as defined by the
+formatting string in `org-html-preamble-format'.
+
+When set to a function, apply this function and insert the
+returned string. The function takes the property list of export
+options as its only argument.
+
+This is included in the document at the top of content section, and
+uses the preamble element and id from `org-html-divs'. The css
+styling is controlled by `org-deck-pre/postamble-styles'.
+
+Setting :deck-preamble in publishing projects will take
+precedence over this variable."
+ :group 'org-export-deck
+ :type '(choice (const :tag "No preamble" nil)
+ (const :tag "Default formatting string" t)
+ (string :tag "Custom formatting string")
+ (function :tag "Function (must return a string)")))
+
+(defvar org-deck-toc-styles
+ (mapconcat
+ 'identity
+ (list
+ "#table-of-contents a {color: inherit;}"
+ "#table-of-contents ul {margin-bottom: 0;}"
+ "#table-of-contents li {padding: 0;}") "\n")
+ "Default css styles used for formatting a table of contents slide.
+Can be overriden in `org-deck-styles'.
+Note that when the headline numbering option is true, a \"list-style: none\"
+is automatically added to avoid both numbers and bullets on the toc entries.")
+
+(defcustom org-deck-styles
+ "
+#title-slide h1 {
+ position: static; padding: 0;
+ margin-top: 10%;
+ -webkit-transform: none;
+ -moz-transform: none;
+ -ms-transform: none;
+ -o-transform: none;
+ transform: none;
+}
+#title-slide h2 {
+ text-align: center;
+ border:none;
+ padding: 0;
+ margin: 0;
+}"
+ "Deck specific CSS styles to include in exported html.
+Defaults to styles for the title page."
+ :group 'org-export-deck
+ :type 'string)
+
+(defcustom org-deck-title-slide-template
+ "<h1>%t</h1>
+<h2>%a</h2>
+<h2>%e</h2>
+<h2>%d</h2>"
+ "Format template to specify title page section.
+See `org-html-postamble-format' for the valid elements which
+can be included.
+
+It will be wrapped in the element defined in the :html-container
+property, and defaults to the value of `org-html-container-element',
+and have the id \"title-slide\"."
+ :group 'org-export-deck
+ :type 'string)
+
+(defun org-deck-toc (depth info)
+ (concat
+ (format "<%s id='table-of-contents' class='slide'>\n"
+ (plist-get info :html-container))
+ (format "<h2>%s</h2>\n" (org-html--translate "Table of Contents" info))
+ (org-html--toc-text
+ (mapcar
+ (lambda (headline)
+ (let* ((class (org-element-property :HTML_CONTAINER_CLASS headline))
+ (section-number
+ (when
+ (and (not (org-export-low-level-p headline info))
+ (org-export-numbered-headline-p headline info))
+ (concat
+ (mapconcat
+ 'number-to-string
+ (org-export-get-headline-number headline info) ".") ". ")))
+ (title
+ (concat
+ section-number
+ (replace-regexp-in-string ; remove any links in headline...
+ "</?a[^>]*>" ""
+ (org-export-data
+ (org-element-property :title headline) info)))))
+ (cons
+ (if (and class (string-match-p "\\<slide\\>" class))
+ (format
+ "<a href='#outline-container-%s'>%s</a>"
+ (or (org-element-property :CUSTOM_ID headline)
+ (concat
+ "sec-"
+ (mapconcat
+ 'number-to-string
+ (org-export-get-headline-number headline info) "-")))
+ title)
+ title)
+ (org-export-get-relative-level headline info))))
+ (org-export-collect-headlines info depth)))
+ (format "</%s>\n" (plist-get info :html-container))))
+
+(defun org-deck--get-packages (info)
+ (let ((prefix (concat (plist-get info :deck-base-url) "/"))
+ (theme (plist-get info :deck-theme))
+ (transition (plist-get info :deck-transition))
+ (include (plist-get info :deck-include-extensions))
+ (exclude (plist-get info :deck-exclude-extensions))
+ (scripts '()) (sheets '()) (snippets '()))
+ (add-to-list 'scripts (concat prefix "jquery-1.7.2.min.js"))
+ (add-to-list 'scripts (concat prefix "core/deck.core.js"))
+ (add-to-list 'scripts (concat prefix "modernizr.custom.js"))
+ (add-to-list 'sheets (concat prefix "core/deck.core.css"))
+ (mapc
+ (lambda (extdir)
+ (let* ((name (file-name-nondirectory extdir))
+ (dir (file-name-as-directory extdir))
+ (path (concat prefix "extensions/" name "/"))
+ (base (format "deck.%s." name)))
+ (when (and (or (eq nil include) (member name include))
+ (not (member name exclude)))
+ (when (file-exists-p (concat dir base "js"))
+ (add-to-list 'scripts (concat path base "js")))
+ (when (file-exists-p (concat dir base "css"))
+ (add-to-list 'sheets (concat path base "css")))
+ (when (file-exists-p (concat dir base "html"))
+ (add-to-list 'snippets (concat dir base "html"))))))
+ (org-deck--find-extensions))
+ (if (not (string-match-p "^[[:space:]]*$" theme))
+ (add-to-list 'sheets
+ (if (file-name-directory theme) theme
+ (format "%sthemes/style/%s" prefix theme))))
+ (if (not (string-match-p "^[[:space:]]*$" transition))
+ (add-to-list
+ 'sheets
+ (if (file-name-directory transition) transition
+ (format "%sthemes/transition/%s" prefix transition))))
+ (list :scripts (nreverse scripts) :sheets (nreverse sheets)
+ :snippets snippets)))
+
+(defun org-deck-inner-template (contents info)
+ "Return body of document string after HTML conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (concat contents "\n"))
+
+(defun org-deck-headline (headline contents info)
+ (let ((org-html-toplevel-hlevel 2)
+ (class (or (org-element-property :HTML_CONTAINER_CLASS headline) ""))
+ (level (org-export-get-relative-level headline info)))
+ (when (and (= 1 level) (not (string-match-p "\\<slide\\>" class)))
+ (org-element-put-property headline :HTML_CONTAINER_CLASS (concat class " slide")))
+ (org-html-headline headline contents info)))
+
+(defun org-deck-item (item contents info)
+ "Transcode an ITEM element from Org to HTML.
+CONTENTS holds the contents of the item. INFO is a plist holding
+contextual information.
+If the containing headline has the property :slide, then
+the \"slide\" class will be added to the to the list element,
+ which will make the list into a \"build\"."
+ (let ((text (org-html-item item contents info)))
+ (if (org-export-get-node-property :STEP item t)
+ (replace-regexp-in-string "^<li>" "<li class='slide'>" text)
+ text)))
+
+(defun org-deck-link (link desc info)
+ (replace-regexp-in-string "href=\"#" "href=\"#outline-container-"
+ (org-html-link link desc info)))
+
+(defun org-deck-template (contents info)
+ "Return complete document string after HTML conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (let ((pkg-info (org-deck--get-packages info))
+ (org-html--pre/postamble-class "deck-status")
+ (info (plist-put
+ (plist-put info :html-preamble (plist-get info :deck-preamble))
+ :html-postamble (plist-get info :deck-postamble))))
+ (mapconcat
+ 'identity
+ (list
+ (let* ((dt (plist-get info :html-doctype))
+ (dt-cons (assoc dt org-html-doctype-alist)))
+ (if dt-cons
+ (cdr dt-cons)
+ dt))
+ (let ((lang (plist-get info :language)))
+ (mapconcat
+ (lambda (x)
+ (apply
+ 'format
+ "<!--%s <html %s lang='%s' xmlns='http://www.w3.org/1999/xhtml'> %s<![endif]-->"
+ x))
+ (list `("[if lt IE 7]>" "class='no-js ie6'" ,lang "")
+ `("[if IE 7]>" "class='no-js ie7'" ,lang "")
+ `("[if IE 8]>" "class='no-js ie8'" ,lang "")
+ `("[if gt IE 8]><!-->" "" ,lang "<!--")) "\n"))
+ "<head>"
+ (org-deck--build-meta-info info)
+ (mapconcat
+ (lambda (sheet)
+ (format
+ "<link rel='stylesheet' href='%s' type='text/css' />" sheet))
+ (plist-get pkg-info :sheets) "\n")
+ (mapconcat
+ (lambda (script)
+ (format
+ "<script src='%s' type='text/javascript'></script>" script))
+ (plist-get pkg-info :scripts) "\n")
+ (org-html--build-mathjax-config info)
+ "<script type='text/javascript'>"
+ " $(document).ready(function () { $.deck('.slide'); });"
+ "</script>"
+ (org-html--build-head info)
+ "<style type='text/css'>"
+ org-deck-toc-styles
+ (when (plist-get info :section-numbers)
+ "#table-of-contents ul li {list-style-type: none;}")
+ (format "#%s, #%s {%s}"
+ (nth 2 (assq 'preamble org-html-divs))
+ (nth 2 (assq 'postamble org-html-divs))
+ (nth 1 (assq 'both org-deck-pre/postamble-styles)))
+ (format "#%s {%s}"
+ (nth 2 (assq 'preamble org-html-divs))
+ (nth 1 (assq 'preamble org-deck-pre/postamble-styles)))
+ (format "#%s {%s}"
+ (nth 2 (assq 'postamble org-html-divs))
+ (nth 1 (assq 'postamble org-deck-pre/postamble-styles)))
+ org-deck-styles
+ "</style>"
+ "</head>"
+ "<body>"
+ (format "<%s id='%s' class='deck-container'>"
+ (nth 1 (assq 'content org-html-divs))
+ (nth 2 (assq 'content org-html-divs)))
+ (org-html--build-pre/postamble 'preamble info)
+ ;; title page
+ (format "<%s id='title-slide' class='slide'>"
+ (plist-get info :html-container))
+ (format-spec org-deck-title-slide-template (org-html-format-spec info))
+ (format "</%s>" (plist-get info :html-container))
+ ;; toc page
+ (let ((depth (plist-get info :with-toc)))
+ (when depth (org-deck-toc depth info)))
+ contents
+ (mapconcat
+ (lambda (snippet)
+ (with-temp-buffer (insert-file-contents snippet)
+ (buffer-string)))
+ (plist-get pkg-info :snippets) "\n")
+ (org-html--build-pre/postamble 'postamble info)
+ (format "</%s>" (nth 1 (assq 'content org-html-divs)))
+ "</body>"
+ "</html>\n") "\n")))
+
+(defun org-deck--build-meta-info (info)
+ "Return meta tags for exported document.
+INFO is a plist used as a communication channel."
+ (let* ((title (org-export-data (plist-get info :title) info))
+ (author (and (plist-get info :with-author)
+ (let ((auth (plist-get info :author)))
+ (and auth (org-export-data auth info)))))
+ (date (and (plist-get info :with-date)
+ (let ((date (org-export-get-date info)))
+ (and date (org-export-data date info)))))
+ (description (plist-get info :description))
+ (keywords (plist-get info :keywords)))
+ (mapconcat
+ 'identity
+ (list
+ (format "<title>%s</title>" title)
+ (format "<meta http-equiv='Content-Type' content='text/html; charset=%s'/>"
+ (or (and org-html-coding-system
+ (fboundp 'coding-system-get)
+ (coding-system-get
+ org-html-coding-system 'mime-charset))
+ "iso-8859-1"))
+ (mapconcat
+ (lambda (attr)
+ (when (< 0 (length (car attr)))
+ (format "<meta name='%s' content='%s'/>\n"
+ (nth 1 attr) (car attr))))
+ (list '("Org-mode" "generator")
+ `(,author "author")
+ `(,description "description")
+ `(,keywords "keywords")) "")) "\n")))
+(defun org-deck-export-as-html
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to an HTML buffer.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"<body>\" and \"</body>\" tags.
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Export is done in a buffer named \"*Org deck.js Export*\", which
+will be displayed when `org-export-show-temporary-export-buffer'
+is non-nil."
+ (interactive)
+ (if async
+ (org-export-async-start
+ (lambda (output)
+ (with-current-buffer (get-buffer-create "*Org deck.js Export*")
+ (erase-buffer)
+ (insert output)
+ (goto-char (point-min))
+ (nxml-mode)
+ (org-export-add-to-stack (current-buffer) 'deck)))
+ `(org-export-as 'deck ,subtreep ,visible-only ,body-only ',ext-plist))
+ (let ((outbuf (org-export-to-buffer
+ 'deck "*Org deck.js Export*"
+ subtreep visible-only body-only ext-plist)))
+ ;; Set major mode.
+ (with-current-buffer outbuf (nxml-mode))
+ (when org-export-show-temporary-export-buffer
+ (switch-to-buffer-other-window outbuf)))))
+
+(defun org-deck-export-to-html
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to a deck.js HTML file.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"<body>\" and \"</body>\" tags.
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Return output file's name."
+ (interactive)
+ (let* ((extension (concat "." org-html-extension))
+ (file (org-export-output-file-name extension subtreep))
+ (org-export-coding-system org-html-coding-system))
+ (if async
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 'deck))
+ (let ((org-export-coding-system org-html-coding-system))
+ `(expand-file-name
+ (org-export-to-file
+ 'deck ,file ,subtreep ,visible-only ,body-only ',ext-plist))))
+ (let ((org-export-coding-system org-html-coding-system))
+ (org-export-to-file
+ 'deck file subtreep visible-only body-only ext-plist)))))
+
+(defun org-deck-publish-to-html (plist filename pub-dir)
+ "Publish an org file to deck.js HTML Presentation.
+FILENAME is the filename of the Org file to be published. PLIST
+is the property list for the given project. PUB-DIR is the
+publishing directory. Returns output file name."
+ (org-publish-org-to 'deck filename ".html" plist pub-dir))
+
+(provide 'ox-deck)
+
+;;; ox-deck.el ends here
diff --git a/contrib/lisp/ox-freemind.el b/contrib/lisp/ox-freemind.el
new file mode 100644
index 0000000..4e90eff
--- /dev/null
+++ b/contrib/lisp/ox-freemind.el
@@ -0,0 +1,536 @@
+;;; ox-freemind.el --- Freemind Mindmap Back-End for Org Export Engine
+
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+
+;; Author: Jambunathan K <kjambunathan at gmail dot com>
+;; Keywords: outlines, hypermedia, calendar, wp
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library implements a Freemind Mindmap back-end for Org generic
+;; exporter.
+
+;; To test it, run:
+;;
+;; M-x org-freemind-export-to-freemind
+;;
+;; in an Org mode buffer. See ox.el for more details on how this
+;; exporter works.
+
+;;; Code:
+
+;;; Dependencies
+
+(require 'ox-html)
+
+
+
+;;; Define Back-End
+
+(org-export-define-derived-backend 'freemind 'html
+ :export-block "FREEMIND"
+ :menu-entry
+ '(?f "Export to Freemind Mindmap"
+ ((?f "As Freemind Mindmap file" org-freemind-export-to-freemind)
+ (?o "As Freemind Mindmap file and open"
+ (lambda (a s v b)
+ (if a (org-freemind-export-to-freemind t s v b)
+ (org-open-file (org-freemind-export-to-freemind nil s v b)))))))
+ :translate-alist '((headline . org-freemind-headline)
+ (template . org-freemind-template)
+ (inner-template . org-freemind-inner-template)
+ (section . org-freemind-section)
+ (entity . org-freemind-entity))
+ :filters-alist '((:filter-options . org-freemind-options-function)
+ (:filter-final-output . org-freemind-final-function)))
+
+
+
+;;; User Configuration Variables
+
+(defgroup org-export-freemind nil
+ "Options for exporting Org mode files to Freemind Mindmap."
+ :tag "Org Export Freemind Mindmap"
+ :group 'org-export)
+
+(defcustom org-freemind-styles
+ '((default . "<node>\n</node>")
+ (0 . "<node COLOR=\"#000000\">\n<font NAME=\"SansSerif\" SIZE=\"20\"/>\n</node>")
+ (1 . "<node COLOR=\"#0033ff\">\n<edge STYLE=\"sharp_bezier\" WIDTH=\"8\"/>\n<font NAME=\"SansSerif\" SIZE=\"18\"/>\n</node>")
+ (2 . "<node COLOR=\"#00b439\">\n<edge STYLE=\"bezier\" WIDTH=\"thin\"/>\n<font NAME=\"SansSerif\" SIZE=\"16\"/>\n</node>")
+ (3 . "<node COLOR=\"#990000\" FOLDED=\"true\">\n<font NAME=\"SansSerif\" SIZE=\"14\"/>\n</node>")
+ (4 . "<node COLOR=\"#111111\">\n</node>"))
+ "List of Freemind node styles.
+Each entry is of the form (STYLE-NAME . STYLE-SPEC). STYLE-NAME
+can be one of an integer (signifying an outline level), a string
+or the symbol `default'. STYLE-SPEC, a string, is a Freemind
+node style."
+ :type '(alist :options (default 0 1 2 3)
+ :key-type (choice :tag "Style tag"
+ (integer :tag "Outline level")
+ (const :tag "Default value" default)
+ (string :tag "Node style"))
+ :value-type (string :tag "Style spec"))
+ :group 'org-export-freemind)
+
+(defcustom org-freemind-style-map-function 'org-freemind-style-map--automatic
+ "Function to map an Org element to it's node style.
+The mapping function takes two arguments an Org ELEMENT and INFO.
+ELEMENT can be one of the following types - `org-data',
+`headline' or `section'. INFO is a plist holding contextual
+information during export. The function must return a STYLE-SPEC
+to be applied to ELEMENT.
+
+See `org-freemind-style-map--automatic' for a sample style
+function. See `org-freemind-styles' for a list of named styles."
+ :type '(radio
+ (function-item org-freemind-style-map--automatic)
+ (function-item org-freemind-style-map--default)
+ function)
+ :group 'org-export-freemind)
+
+(defcustom org-freemind-section-format 'note
+ "Specify how outline sections are to be formatted.
+If `inline', append it to the contents of it's heading node. If
+`note', attach it as a note to it's heading node. If `node',
+attach it as a separate node to it's heading node.
+
+Use `note', if the input Org file contains large sections. Use
+`node', if the Org file contains mid-sized sections that need to
+stand apart. Otherwise, use `inline'."
+ :type '(choice
+ (const :tag "Append to outline title" inline)
+ (const :tag "Attach as a note" note)
+ (const :tag "Create a separate node" node))
+ :group 'org-export-freemind)
+
+;;;; Debugging
+
+(defcustom org-freemind-pretty-output nil
+ "Enable this to generate pretty Freemind Mindmap."
+ :type 'boolean
+ :group 'org-export-freemind)
+
+
+;;; Internal Functions
+
+;;;; XML Manipulation
+
+(defun org-freemind--serialize (parsed-xml &optional contents)
+ "Convert PARSED-XML in to XML string.
+PARSED-XML is a parse tree as returned by
+`libxml-parse-xml-region'. CONTENTS is an optional string.
+
+Ignore CONTENTS, if PARSED-XML is not a sole XML element.
+Otherwise, append CONTENTS to the contents of top-level element
+in PARSED-XML.
+
+This is an inverse function of `libxml-parse-xml-region'.
+
+For purposes of Freemind export, PARSED-XML is a node style
+specification - \"<node ...>...</node>\" - as a parse tree."
+ (when contents
+ (assert (symbolp (car parsed-xml))))
+ (cond
+ ((null parsed-xml) "")
+ ((stringp parsed-xml) parsed-xml)
+ ((symbolp (car parsed-xml))
+ (let ((attributes (mapconcat
+ (lambda (av)
+ (format "%s=\"%s\"" (car av) (cdr av)))
+ (cadr parsed-xml) " ")))
+ (if (or (cddr parsed-xml) contents)
+ (format "\n<%s%s>%s\n</%s>"
+ (car parsed-xml)
+ (if (string= attributes "") "" (concat " " attributes))
+ (concat (org-freemind--serialize (cddr parsed-xml))
+ contents )
+ (car parsed-xml))
+ (format "\n<%s%s/>"
+ (car parsed-xml)
+ (if (string= attributes "") "" (concat " " attributes))))))
+ (t (mapconcat #'org-freemind--serialize parsed-xml ""))))
+
+(defun org-freemind--parse-xml (xml-string)
+ "Return parse tree for XML-STRING using `libxml-parse-xml-region'.
+For purposes of Freemind export, XML-STRING is a node style
+specification - \"<node ...>...</node>\" - as a string."
+ (with-temp-buffer
+ (insert (or xml-string ""))
+ (libxml-parse-xml-region (point-min) (point-max))))
+
+
+;;;; Style mappers :: Default and Automatic layout
+
+(defun org-freemind-style-map--automatic (element info)
+ "Return a node style corresponding to relative outline level of ELEMENT.
+ELEMENT can be any of the following types - `org-data',
+`headline' or `section'. See `org-freemind-styles' for style
+mappings of different outline levels."
+ (let ((style-name
+ (case (org-element-type element)
+ (headline
+ (org-export-get-relative-level element info))
+ (section
+ (let ((parent (org-export-get-parent-headline element)))
+ (if (not parent) 1
+ (1+ (org-export-get-relative-level parent info)))))
+ (t 0))))
+ (or (assoc-default style-name org-freemind-styles)
+ (assoc-default 'default org-freemind-styles)
+ "<node></node>")))
+
+(defun org-freemind-style-map--default (element info)
+ "Return the default style for all ELEMENTs.
+ELEMENT can be any of the following types - `org-data',
+`headline' or `section'. See `org-freemind-styles' for current
+value of default style."
+ (or (assoc-default 'default org-freemind-styles)
+ "<node></node>"))
+
+
+;;;; Helpers :: Retrieve, apply Freemind styles
+
+(defun org-freemind--get-node-style (element info)
+ "Return Freemind node style applicable for HEADLINE.
+ELEMENT is an Org element of type `org-data', `headline' or
+`section'. INFO is a plist holding contextual information."
+ (unless (fboundp org-freemind-style-map-function)
+ (setq org-freemind-style-map-function 'org-freemind-style-map--default))
+ (let ((style (funcall org-freemind-style-map-function element info)))
+ ;; Sanitize node style.
+
+ ;; Loop through the attributes of node element and purge those
+ ;; attributes that look suspicious. This is an extra bit of work
+ ;; that allows one to copy verbatim node styles from an existing
+ ;; Freemind Mindmap file without messing with the exported data.
+ (let* ((data (org-freemind--parse-xml style))
+ (attributes (cadr data))
+ (ignored-attrs '(POSITION FOLDED TEXT CREATED ID
+ MODIFIED)))
+ (let (attr)
+ (while (setq attr (pop ignored-attrs))
+ (setq attributes (assq-delete-all attr attributes))))
+ (when data (setcar (cdr data) attributes))
+ (org-freemind--serialize data))))
+
+(defun org-freemind--build-stylized-node (style-1 style-2 &optional contents)
+ "Build a Freemind node with style STYLE-1 + STYLE-2 and add CONTENTS to it.
+STYLE-1 and STYLE-2 are Freemind node styles as a string.
+STYLE-1 is the base node style and STYLE-2 is the overriding
+style that takes precedence over STYLE-1. CONTENTS is a string.
+
+Return value is a Freemind node with following properties:
+
+ 1. The attributes of \"<node ...> </node>\" element is the union
+ of corresponding attributes of STYLE-1 and STYLE-2. When
+ STYLE-1 and STYLE-2 specify values for the same attribute
+ name, choose the attribute value from STYLE-2.
+
+ 2. The children of \"<node ...> </node>\" element is the union of
+ top-level children of STYLE-1 and STYLE-2 with CONTENTS
+ appended to it. When STYLE-1 and STYLE-2 share a child
+ element of same type, the value chosen is that from STYLE-2.
+
+For example, merging with following parameters
+
+ STYLE-1 =>
+ <node COLOR=\"#00b439\" STYLE=\"Bubble\">
+ <edge STYLE=\"bezier\" WIDTH=\"thin\"/>
+ <font NAME=\"SansSerif\" SIZE=\"16\"/>
+ </node>
+
+ STYLE-2 =>
+ <node COLOR=\"#990000\" FOLDED=\"true\">
+ <font NAME=\"SansSerif\" SIZE=\"14\"/>
+ </node>
+
+ CONTENTS =>
+ <attribute NAME=\"ORGTAG\" VALUE=\"@home\"/>
+
+will result in following node:
+
+ RETURN =>
+ <node STYLE=\"Bubble\" COLOR=\"#990000\" FOLDED=\"true\">
+ <edge STYLE=\"bezier\" WIDTH=\"thin\"/>
+ <font NAME=\"SansSerif\" SIZE=\"14\"/>
+ <attribute NAME=\"ORGTAG\" VALUE=\"@home\"/>
+ </node>."
+ (let* ((data1 (org-freemind--parse-xml (or style-1 "")))
+ (data2 (org-freemind--parse-xml (or style-2 "")))
+ (attr1 (cadr data1))
+ (attr2 (cadr data2))
+ (merged-attr attr2)
+ (children1 (cddr data1))
+ (children2 (cddr data2))
+ (merged-children children2))
+ (let (attr)
+ (while (setq attr (pop attr1))
+ (unless (assq (car attr) merged-attr)
+ (push attr merged-attr))))
+ (let (child)
+ (while (setq child (pop children1))
+ (when (or (stringp child) (not (assq (car child) merged-children)))
+ (push child merged-children))))
+ (let ((merged-data (nconc (list 'node merged-attr) merged-children)))
+ (org-freemind--serialize merged-data contents))))
+
+
+;;;; Helpers :: Node contents
+
+(defun org-freemind--richcontent (type contents &optional css-style)
+ (let* ((type (case type
+ (note "NOTE")
+ (node "NODE")
+ (t "NODE")))
+ (contents (org-trim contents)))
+ (if (string= (org-trim contents) "") ""
+ (format "\n<richcontent TYPE=\"%s\">%s\n</richcontent>"
+ type
+ (format "\n<html>\n<head>%s\n</head>\n%s\n</html>"
+ (or css-style "")
+ (format "<body>\n%s\n</body>" contents))))))
+
+(defun org-freemind--build-node-contents (element contents info)
+ (let* ((title (case (org-element-type element)
+ (headline
+ (org-element-property :title element))
+ (org-data
+ (plist-get info :title))
+ (t (error "Shouldn't come here."))))
+ (element-contents (org-element-contents element))
+ (section (assoc 'section element-contents))
+ (section-contents
+ (let* ((translations
+ (nconc (list (cons 'section
+ (lambda (section contents info)
+ contents)))
+ (plist-get info :translate-alist))))
+ (org-export-data-with-translations section translations info)))
+ (itemized-contents-p (let ((first-child-headline
+ (org-element-map element-contents
+ 'headline 'identity info t)))
+ (when first-child-headline
+ (org-export-low-level-p first-child-headline
+ info))))
+ (node-contents (concat section-contents
+ (when itemized-contents-p
+ contents))))
+ (concat (let ((title (org-export-data title info)))
+ (case org-freemind-section-format
+ (inline
+ (org-freemind--richcontent
+ 'node (concat (format "\n<h2>%s</h2>" title)
+ node-contents) ))
+ (note
+ (concat (org-freemind--richcontent
+ 'node (format "\n<p>%s\n</p>" title))
+ (org-freemind--richcontent
+ 'note node-contents)))
+ (node
+ (concat
+ (org-freemind--richcontent
+ 'node (format "\n<p>%s\n</p>" title))
+ (when section
+ (org-freemind--build-stylized-node
+ (org-freemind--get-node-style section info) nil
+ (org-freemind--richcontent 'node node-contents)))))))
+ (unless itemized-contents-p
+ contents))))
+
+
+
+;;; Template
+
+(defun org-freemind-template (contents info)
+ "Return complete document string after Freemind Mindmap conversion.
+CONTENTS is the transcoded contents string. RAW-DATA is the
+original parsed data. INFO is a plist holding export options."
+ (format
+ "<map version=\"0.9.0\">\n%s\n</map>"
+ (org-freemind--build-stylized-node
+ (org-freemind--get-node-style nil info) nil
+ (let ((org-data (plist-get info :parse-tree)))
+ (org-freemind--build-node-contents org-data contents info)))))
+
+(defun org-freemind-inner-template (contents info)
+ "Return body of document string after Freemind Mindmap conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ contents)
+
+;;;; Tags
+
+(defun org-freemind--tags (tags)
+ (mapconcat (lambda (tag)
+ (format "\n<attribute NAME=\"%s\" VALUE=\"%s\"/>" tag ""))
+ tags "\n"))
+
+
+
+;;; Transcode Functions
+
+;;;; Entity
+
+(defun org-freemind-entity (entity contents info)
+ "Transcode an ENTITY object from Org to Freemind Mindmap.
+CONTENTS are the definition itself. INFO is a plist holding
+contextual information."
+ (org-element-property :utf-8 entity))
+
+;;;; Headline
+
+(defun org-freemind-headline (headline contents info)
+ "Transcode a HEADLINE element from Org to Freemind Mindmap.
+CONTENTS holds the contents of the headline. INFO is a plist
+holding contextual information."
+ ;; Empty contents?
+ (setq contents (or contents ""))
+ (let* ((numberedp (org-export-numbered-headline-p headline info))
+ (level (org-export-get-relative-level headline info))
+ (text (org-export-data (org-element-property :title headline) info))
+ (todo (and (plist-get info :with-todo-keywords)
+ (let ((todo (org-element-property :todo-keyword headline)))
+ (and todo (org-export-data todo info)))))
+ (todo-type (and todo (org-element-property :todo-type headline)))
+ (tags (and (plist-get info :with-tags)
+ (org-export-get-tags headline info)))
+ (priority (and (plist-get info :with-priority)
+ (org-element-property :priority headline)))
+ (section-number (and (not (org-export-low-level-p headline info))
+ (org-export-numbered-headline-p headline info)
+ (mapconcat 'number-to-string
+ (org-export-get-headline-number
+ headline info) ".")))
+ ;; Create the headline text.
+ (full-text (org-export-data (org-element-property :title headline)
+ info))
+ ;; Headline order (i.e, first digit of the section number)
+ (headline-order (car (org-export-get-headline-number headline info))))
+ (cond
+ ;; Case 1: This is a footnote section: ignore it.
+ ((org-element-property :footnote-section-p headline) nil)
+ ;; Case 2. This is a deep sub-tree, export it as a list item.
+ ;; Delegate the actual export to `html' backend.
+ ((org-export-low-level-p headline info)
+ (org-html-headline headline contents info))
+ ;; Case 3. Standard headline. Export it as a section.
+ (t
+ (let* ((section-number (mapconcat 'number-to-string
+ (org-export-get-headline-number
+ headline info) "-"))
+ (ids (remove 'nil
+ (list (org-element-property :CUSTOM_ID headline)
+ (concat "sec-" section-number)
+ (org-element-property :ID headline))))
+ (preferred-id (car ids))
+ (extra-ids (cdr ids))
+ (left-p (zerop (% headline-order 2))))
+ (org-freemind--build-stylized-node
+ (org-freemind--get-node-style headline info)
+ (format "<node ID=\"%s\" POSITION=\"%s\" FOLDED=\"%s\">\n</node>"
+ preferred-id
+ (if left-p "left" "right")
+ (if (= level 1) "true" "false"))
+ (concat (org-freemind--build-node-contents headline contents info)
+ (org-freemind--tags tags))))))))
+
+
+;;;; Section
+
+(defun org-freemind-section (section contents info)
+ "Transcode a SECTION element from Org to Freemind Mindmap.
+CONTENTS holds the contents of the section. INFO is a plist
+holding contextual information."
+ (let ((parent (org-export-get-parent-headline section)))
+ (when (and parent (org-export-low-level-p parent info))
+ contents)))
+
+
+
+;;; Filter Functions
+
+(defun org-freemind-final-function (contents backend info)
+ "Return CONTENTS as pretty XML using `indent-region'."
+ (if (not org-freemind-pretty-output) contents
+ (with-temp-buffer
+ (nxml-mode)
+ (insert contents)
+ (indent-region (point-min) (point-max))
+ (buffer-substring-no-properties (point-min) (point-max)))))
+
+(defun org-freemind-options-function (info backend)
+ "Install script in export options when appropriate.
+EXP-PLIST is a plist containing export options. BACKEND is the
+export back-end currently used."
+ ;; Freemind/Freeplane doesn't seem to like named html entities in
+ ;; richcontent. For now, turn off smart quote processing so that
+ ;; entities like "&rsquo;" & friends are avoided in the exported
+ ;; output.
+ (plist-put info :with-smart-quotes nil))
+
+
+
+;;; End-user functions
+
+;;;###autoload
+(defun org-freemind-export-to-freemind
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to a Freemind Mindmap file.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"<body>\" and \"</body>\" tags.
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Return output file's name."
+ (interactive)
+ (let* ((extension (concat ".mm" ))
+ (file (org-export-output-file-name extension subtreep)))
+ (if async
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 'freemind))
+ (let ((org-export-coding-system 'utf-8))
+ `(expand-file-name
+ (org-export-to-file
+ 'freemind ,file ,subtreep ,visible-only ,body-only ',ext-plist))))
+ (let ((org-export-coding-system 'utf-8))
+ (org-export-to-file
+ 'freemind file subtreep visible-only body-only ext-plist)))))
+
+(provide 'ox-freemind)
+
+;;; ox-freemind.el ends here
diff --git a/contrib/lisp/org-e-groff.el b/contrib/lisp/ox-groff.el
index 756a818..ef54700 100644
--- a/contrib/lisp/org-e-groff.el
+++ b/contrib/lisp/ox-groff.el
@@ -1,11 +1,12 @@
-;; org-e-groff.el --- Groff Back-End For Org Export Engine
+;;; ox-groff.el --- Groff Back-End for Org Export Engine
-;; Copyright (C) 2011-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2011-2013 Free Software Foundation, Inc.
;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
;; Author: Luis R Anaya <papoanaya aroba hot mail punto com>
;; Keywords: outlines, hypermedia, calendar, wp
-;;
+
+;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -21,16 +22,15 @@
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
-;; This library implements a Groff Memorandum Macro back-end for
-;; Org generic exporter.
+;; This library implements a Groff Memorandum Macro back-end for Org
+;; generic exporter.
;;
;; To test it, run
;;
-;; M-: (org-export-to-buffer 'e-groff "*Test e-Groff*") RET
+;; M-: (org-export-to-buffer 'groff "*Test Groff*") RET
;;
;; in an org-mode buffer then switch to the buffer to see the Groff
-;; export. See contrib/lisp/org-export.el for more details on how
-;; this exporter works.
+;; export. See ox.el for more details on how this exporter works.
;;
;; It introduces two new buffer keywords: "GROFF_CLASS" and
;; "GROFF_CLASS_OPTIONS".
@@ -38,96 +38,93 @@
;;; Code:
(eval-when-compile (require 'cl))
+(require 'ox)
-(defvar org-export-groff-default-packages-alist)
-(defvar org-export-groff-packages-alist)
-
-(require 'org-export)
+(defvar orgtbl-exp-regexp)
;;; Define Back-End
-(defvar org-e-groff-translate-alist
- '((babel-call . org-e-groff-babel-call)
- (bold . org-e-groff-bold)
- (center-block . org-e-groff-center-block)
- (clock . org-e-groff-clock)
- (code . org-e-groff-code)
- (comment . org-e-groff-comment)
- (comment-block . org-e-groff-comment-block)
- (drawer . org-e-groff-drawer)
- (dynamic-block . org-e-groff-dynamic-block)
- (entity . org-e-groff-entity)
- (example-block . org-e-groff-example-block)
- (export-block . org-e-groff-export-block)
- (export-snippet . org-e-groff-export-snippet)
- (fixed-width . org-e-groff-fixed-width)
- (footnote-definition . org-e-groff-footnote-definition)
- (footnote-reference . org-e-groff-footnote-reference)
- (headline . org-e-groff-headline)
- (horizontal-rule . org-e-groff-horizontal-rule)
- (inline-babel-call . org-e-groff-inline-babel-call)
- (inline-src-block . org-e-groff-inline-src-block)
- (inlinetask . org-e-groff-inlinetask)
- (italic . org-e-groff-italic)
- (item . org-e-groff-item)
- (keyword . org-e-groff-keyword)
- (groff-environment . org-e-groff-groff-environment)
- (groff-fragment . org-e-groff-groff-fragment)
- (line-break . org-e-groff-line-break)
- (link . org-e-groff-link)
- (macro . org-e-groff-macro)
- (paragraph . org-e-groff-paragraph)
- (plain-list . org-e-groff-plain-list)
- (plain-text . org-e-groff-plain-text)
- (planning . org-e-groff-planning)
- (property-drawer . org-e-groff-property-drawer)
- (quote-block . org-e-groff-quote-block)
- (quote-section . org-e-groff-quote-section)
- (radio-target . org-e-groff-radio-target)
- (section . org-e-groff-section)
- (special-block . org-e-groff-special-block)
- (src-block . org-e-groff-src-block)
- (statistics-cookie . org-e-groff-statistics-cookie)
- (strike-through . org-e-groff-strike-through)
- (subscript . org-e-groff-subscript)
- (superscript . org-e-groff-superscript)
- (table . org-e-groff-table)
- (table-cell . org-e-groff-table-cell)
- (table-row . org-e-groff-table-row)
- (target . org-e-groff-target)
- (template . org-e-groff-template)
- (timestamp . org-e-groff-timestamp)
- (underline . org-e-groff-underline)
- (verbatim . org-e-groff-verbatim)
- (verse-block . org-e-groff-verse-block))
- "Alist between element or object types and translators.")
-
-(defconst org-e-groff-options-alist
- '((:date "DATE" nil org-e-groff-date-format t)
- (:groff-class "GROFF_CLASS" nil org-e-groff-default-class t)
+(org-export-define-backend 'groff
+ '((bold . org-groff-bold)
+ (center-block . org-groff-center-block)
+ (clock . org-groff-clock)
+ (code . org-groff-code)
+ (comment . (lambda (&rest args) ""))
+ (comment-block . (lambda (&rest args) ""))
+ (drawer . org-groff-drawer)
+ (dynamic-block . org-groff-dynamic-block)
+ (entity . org-groff-entity)
+ (example-block . org-groff-example-block)
+ (export-block . org-groff-export-block)
+ (export-snippet . org-groff-export-snippet)
+ (fixed-width . org-groff-fixed-width)
+ (footnote-definition . org-groff-footnote-definition)
+ (footnote-reference . org-groff-footnote-reference)
+ (headline . org-groff-headline)
+ (horizontal-rule . org-groff-horizontal-rule)
+ (inline-src-block . org-groff-inline-src-block)
+ (inlinetask . org-groff-inlinetask)
+ (italic . org-groff-italic)
+ (item . org-groff-item)
+ (keyword . org-groff-keyword)
+ (line-break . org-groff-line-break)
+ (link . org-groff-link)
+ (paragraph . org-groff-paragraph)
+ (plain-list . org-groff-plain-list)
+ (plain-text . org-groff-plain-text)
+ (planning . org-groff-planning)
+ (property-drawer . (lambda (&rest args) ""))
+ (quote-block . org-groff-quote-block)
+ (quote-section . org-groff-quote-section)
+ (radio-target . org-groff-radio-target)
+ (section . org-groff-section)
+ (special-block . org-groff-special-block)
+ (src-block . org-groff-src-block)
+ (statistics-cookie . org-groff-statistics-cookie)
+ (strike-through . org-groff-strike-through)
+ (subscript . org-groff-subscript)
+ (superscript . org-groff-superscript)
+ (table . org-groff-table)
+ (table-cell . org-groff-table-cell)
+ (table-row . org-groff-table-row)
+ (target . org-groff-target)
+ (template . org-groff-template)
+ (timestamp . org-groff-timestamp)
+ (underline . org-groff-underline)
+ (verbatim . org-groff-verbatim)
+ (verse-block . org-groff-verse-block))
+ :export-block "GROFF"
+ :menu-entry
+ '(?g "Export to GROFF"
+ ((?g "As GROFF file" org-groff-export-to-groff)
+ (?p "As PDF file" org-groff-export-to-pdf)
+ (?o "As PDF file and open"
+ (lambda (a s v b)
+ (if a (org-groff-export-to-pdf t s v b)
+ (org-open-file (org-groff-export-to-pdf nil s v b)))))))
+ :options-alist
+ '((:groff-class "GROFF_CLASS" nil org-groff-default-class t)
(:groff-class-options "GROFF_CLASS_OPTIONS" nil nil t)
- (:groff-header-extra "GROFF_HEADER" nil nil newline))
-"Alist between Groff export properties and ways to set them.
-See `org-export-options-alist' for more information on the
-structure of the values.")
+ (:groff-header-extra "GROFF_HEADER" nil nil newline)))
+
;;; User Configurable Variables
-(defgroup org-export-e-groff nil
+(defgroup org-export-groff nil
"Options for exporting Org mode files to Groff."
:tag "Org Export Groff"
:group 'org-export)
;;; Preamble
-(defcustom org-e-groff-default-class "internal"
+(defcustom org-groff-default-class "internal"
"The default Groff class."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(string :tag "Groff class"))
-(defcustom org-e-groff-classes
+(defcustom org-groff-classes
'(("file" ".MT 1"
(:heading 'default :type "memo" :last-section "toc"))
("internal" ".MT 0"
@@ -166,7 +163,7 @@ structure of the values.")
"This list describes the attributes for the documents being created.
It allows for the creation of new "
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(repeat
(list (string :tag "Document Type")
(string :tag "Header")
@@ -175,19 +172,12 @@ structure of the values.")
(list :tag "Heading")
(function :tag "Hook computing sectioning"))))))
-
-(defcustom org-e-groff-date-format
- (format-time-string "%Y-%m-%d")
- "Format string for .ND "
- :group 'org-export-e-groff
- :type 'boolean)
-
;;; Headline
-(defconst org-e-groff-special-tags
+(defconst org-groff-special-tags
'("FROM" "TO" "ABSTRACT" "APPENDIX" "BODY" "NS"))
-(defcustom org-e-groff-format-headline-function nil
+(defcustom org-groff-format-headline-function nil
"Function to format headline text.
This function will be called with 5 arguments:
@@ -202,8 +192,8 @@ The function result will be used in the section format string.
As an example, one could set the variable to the following, in
order to reproduce the default set-up:
-\(defun org-e-groff-format-headline (todo todo-type priority text tags)
- \"Default format function for an headline.\"
+\(defun org-groff-format-headline (todo todo-type priority text tags)
+ \"Default format function for a headline.\"
\(concat (when todo
\(format \"\\fB%s\\fP \" todo))
\(when priority
@@ -212,31 +202,31 @@ order to reproduce the default set-up:
\(when tags
\(format \" %s \"
\(mapconcat 'identity tags \":\"))))"
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'function)
;;; Timestamps
-(defcustom org-e-groff-active-timestamp-format "\\fI%s\\fP"
+(defcustom org-groff-active-timestamp-format "\\fI%s\\fP"
"A printf format string to be applied to active timestamps."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'string)
-(defcustom org-e-groff-inactive-timestamp-format "\\fI%s\\fP"
+(defcustom org-groff-inactive-timestamp-format "\\fI%s\\fP"
"A printf format string to be applied to inactive timestamps."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'string)
-(defcustom org-e-groff-diary-timestamp-format "\\fI%s\\fP"
+(defcustom org-groff-diary-timestamp-format "\\fI%s\\fP"
"A printf format string to be applied to diary timestamps."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'string)
;;; Links
-(defcustom org-e-groff-inline-image-rules
- '(("file" . "\\.\\(pdf\\|ps\\|eps\\|pic\\)\\'")
- ("fuzzy" . "\\.\\(pdf\\|ps\\|eps\\|pic\\)\\'"))
+(defcustom org-groff-inline-image-rules
+ '(("file" . "\\.\\(jpg\\|png\\|pdf\\|ps\\|eps\\|pic\\)\\'")
+ ("fuzzy" . "\\.\\(jpg\\|png\\|pdf\\|ps\\|eps\\|pic\\)\\'"))
"Rules characterizing image files that can be inlined into Groff.
A rule consists in an association whose key is the type of link
@@ -248,41 +238,41 @@ depend on the way the Groff file is processed. When used with
pdfgroff, pdf, jpg and png images are OK. When processing
through dvi to Postscript, only ps and eps are allowed. The
default we use here encompasses both."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(alist :key-type (string :tag "Type")
:value-type (regexp :tag "Path")))
-(defcustom org-e-groff-link-with-unknown-path-format "\\fI%s\\fP"
+(defcustom org-groff-link-with-unknown-path-format "\\fI%s\\fP"
"Format string for links with unknown path type."
:group 'org-export-groff
:type 'string)
;;; Tables
-(defcustom org-e-groff-tables-centered t
+(defcustom org-groff-tables-centered t
"When non-nil, tables are exported in a center environment."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'boolean)
-(defcustom org-e-groff-tables-verbatim nil
+(defcustom org-groff-tables-verbatim nil
"When non-nil, tables are exported verbatim."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'boolean)
-(defcustom org-e-groff-table-scientific-notation "%sE%s"
+(defcustom org-groff-table-scientific-notation "%sE%s"
"Format string to display numbers in scientific notation.
The format should have \"%s\" twice, for mantissa and exponent
\(i.e. \"%s\\\\times10^{%s}\").
When nil, no transformation is made."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(choice
(string :tag "Format string")
(const :tag "No formatting")))
;;; Text markup
-(defcustom org-e-groff-text-markup-alist
+(defcustom org-groff-text-markup-alist
'((bold . "\\fB%s\\fP")
(code . "\\fC%s\\fP")
(italic . "\\fI%s\\fP")
@@ -297,13 +287,13 @@ a formatting string to wrap fontified text with it.
If no association can be found for a given markup, text will be
returned as-is."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'alist
:options '(bold code italic strike-through underline verbatim))
;;; Drawers
-(defcustom org-e-groff-format-drawer-function nil
+(defcustom org-groff-format-drawer-function nil
"Function called to format a drawer in Groff code.
The function must accept two parameters:
@@ -315,15 +305,15 @@ The function should return the string to be exported.
For example, the variable could be set to the following function
in order to mimic default behaviour:
-\(defun org-e-groff-format-drawer-default \(name contents\)
+\(defun org-groff-format-drawer-default \(name contents\)
\"Format a drawer element for Groff export.\"
contents\)"
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'function)
;;; Inlinetasks
-(defcustom org-e-groff-format-inlinetask-function nil
+(defcustom org-groff-format-inlinetask-function nil
"Function called to format an inlinetask in Groff code.
The function must accept six parameters:
@@ -339,7 +329,7 @@ The function should return the string to be exported.
For example, the variable could be set to the following function
in order to mimic default behaviour:
-\(defun org-e-groff-format-inlinetask \(todo type priority name tags contents\)
+\(defun org-groff-format-inlinetask \(todo type priority name tags contents\)
\"Format an inline task element for Groff export.\"
\(let ((full-title
\(concat
@@ -355,17 +345,17 @@ in order to mimic default behaviour:
\"%s\"
\".DE\")
full-title contents))"
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'function)
;; Src blocks
-(defcustom org-e-groff-source-highlight nil
+(defcustom org-groff-source-highlight nil
"Use GNU source highlight to embellish source blocks "
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'boolean)
-(defcustom org-e-groff-source-highlight-langs
+(defcustom org-groff-source-highlight-langs
'((emacs-lisp "lisp") (lisp "lisp") (clojure "lisp")
(scheme "scheme")
(c "c") (cc "cpp") (csharp "csharp") (d "d")
@@ -390,13 +380,13 @@ The value is the string that should be inserted as the language
parameter for the listings package. If the mode name and the
listings name are the same, the language does not need an entry
in this list - but it does not hurt if it is present."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(repeat
(list
(symbol :tag "Major mode ")
(string :tag "Listings language"))))
-(defcustom org-e-groff-source-highlight-options nil
+(defcustom org-groff-source-highlight-options nil
"Association list of options for the groff listings package.
These options are supplied as a comma-separated list to the
@@ -404,7 +394,7 @@ These options are supplied as a comma-separated list to the
a list containing two strings: the name of the option, and the
value. For example,
- (setq org-e-groff-source-highlight-options
+ (setq org-groff-source-highlight-options
'((\"basicstyle\" \"\\small\")
(\"keywordstyle\" \"\\color{black}\\bfseries\\underbar\")))
@@ -413,19 +403,19 @@ black keywords.
Note that the same options will be applied to blocks of all
languages."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(repeat
(list
(string :tag "Listings option name ")
(string :tag "Listings option value"))))
-(defvar org-e-groff-custom-lang-environments nil
+(defvar org-groff-custom-lang-environments nil
"Alist mapping languages to language-specific Groff environments.
It is used during export of src blocks by the listings and
groff packages. For example,
- \(setq org-e-groff-custom-lang-environments
+ \(setq org-groff-custom-lang-environments
'\(\(python \"pythoncode\"\)\)\)
would have the effect that if org encounters begin_src python
@@ -434,45 +424,13 @@ language.")
;;; Plain text
-(defcustom org-e-groff-quotes
- '(("fr"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "«~")
- ("\\(\\S-\\)\"" . "~»")
- ("\\(\\s-\\|(\\|^\\)'" . "'"))
- ("en"
- ("\\(\\s-\\|[[(]\\|^\\)\"" . "``")
- ("\\(\\S-\\)\"" . "''")
- ("\\(\\s-\\|(\\|^\\)'" . "`")))
- "Alist for quotes to use when converting english double-quotes.
-
-The CAR of each item in this alist is the language code.
-The CDR of each item in this alist is a list of three CONS:
-- the first CONS defines the opening quote;
-- the second CONS defines the closing quote;
-- the last CONS defines single quotes.
-
-For each item in a CONS, the first string is a regexp
-for allowed characters before/after the quote, the second
-string defines the replacement string for this quote."
- :group 'org-export-e-groff
- :type '(list
- (cons :tag "Opening quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))
- (cons :tag "Closing quote"
- (string :tag "Regexp for char after ")
- (string :tag "Replacement quote "))
- (cons :tag "Single quote"
- (string :tag "Regexp for char before")
- (string :tag "Replacement quote "))))
-
-(defcustom org-e-groff-special-char
+(defcustom org-groff-special-char
'(("(c)" . "\\\\(co")
("(tm)" . "\\\\(tm")
("(rg)" . "\\\\(rg"))
"CONS list in which the value of the car
is replace on the value of the CDR. "
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(list
(cons :tag "Character Subtitute"
(string :tag "Original Character Group")
@@ -480,7 +438,7 @@ string defines the replacement string for this quote."
;;; Compilation
-(defcustom org-e-groff-pdf-process
+(defcustom org-groff-pdf-process
'("pic %f | tbl | eqn | groff -mm | ps2pdf - > %b.pdf"
"pic %f | tbl | eqn | groff -mm | ps2pdf - > %b.pdf"
"pic %f | tbl | eqn | groff -mm | ps2pdf - > %b.pdf")
@@ -503,89 +461,73 @@ extension) and %o by the base directory of the file."
"pic %f | tbl | eqn | groff -mm | ps2pdf - > %b.pdf"))
(function)))
-(defcustom org-e-groff-logfiles-extensions
+(defcustom org-groff-logfiles-extensions
'("aux" "idx" "log" "out" "toc" "nav" "snm" "vrb")
"The list of file extensions to consider as Groff logfiles."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type '(repeat (string :tag "Extension")))
-(defcustom org-e-groff-remove-logfiles t
+(defcustom org-groff-remove-logfiles t
"Non-nil means remove the logfiles produced by PDF production.
These are the .aux, .log, .out, and .toc files."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'boolean)
-(defcustom org-e-groff-organization "Org User"
+(defcustom org-groff-organization "Org User"
"Name of the organization used to populate the .AF command."
- :group 'org-export-e-groff
+ :group 'org-export-groff
:type 'string)
-
-;; Adding GROFF as a block parser to make sure that its contents
-;; does not execute
-
-(add-to-list 'org-element-block-name-alist
- '("GROFF" . org-element-export-block-parser))
+(defcustom org-groff-raster-to-ps nil
+ "Command used to convert raster to EPS. Nil for no conversion. Make sure that
+ `org-groff-inline-image-rules' is adjusted accordingly if not conversion is being
+ done. In this case, remove the entries for jpg and png in the file and fuzzy lists."
+ :group 'org-export-groff
+ :type '(choice
+ (repeat :tag "Shell Command Sequence" (string :tag "Shell Command"))
+ (const :tag "sam2p" "a=%s;b=%s;sam2p ${a} ${b} ;grep -v BeginData ${b} > b_${b};mv b_${b} ${b}" )
+ (const :tag "NetPNM" "a=%s;b=%s;pngtopnm ${a} | pnmtops -noturn > ${b}" )
+ (const :tag "None" nil)))
-(defvar org-e-groff-registered-references nil)
-(defvar org-e-groff-special-content nil)
+(defvar org-groff-registered-references nil)
+(defvar org-groff-special-content nil)
;;; Internal Functions
-(defun org-e-groff--caption/label-string (caption label info)
- "Return caption and label Groff string for floats.
-
-CAPTION is a cons cell of secondary strings, the car being the
-standard caption and the cdr its short form. LABEL is a string
-representing the label. INFO is a plist holding contextual
-information.
-
-If there's no caption nor label, return the empty string.
-
-For non-floats, see `org-e-groff--wrap-label'."
- (let ((label-str ""))
- (cond
- ((and (not caption) (not label)) "")
- ((not caption) (format "\\fI%s\\fP" label))
- ;; Option caption format with short name.
- ((cdr caption)
- (format "%s\n.br\n%s - %s\n"
- (org-export-data (cdr caption) info)
- label-str
- (org-export-data (car caption) info)))
- ;; Standard caption format.
- (t (format "\\fR%s\\fP"
- (org-export-data (car caption) info))))))
-
-(defun org-e-groff--quotation-marks (text info)
- "Export quotation marks depending on language conventions.
-TEXT is a string containing quotation marks to be replaced. INFO
-is a plist used as a communication channel."
- (mapc (lambda(l)
- (let ((start 0))
- (while (setq start (string-match (car l) text start))
- (let ((new-quote (concat (match-string 1 text) (cdr l))))
- (setq text (replace-match new-quote t t text))))))
- (cdr (or (assoc (plist-get info :language) org-e-groff-quotes)
- ;; Falls back on English.
- (assoc "en" org-e-groff-quotes))))
- text)
-
-(defun org-e-groff--wrap-label (element output)
+(defun org-groff--caption/label-string (element info)
+ "Return caption and label Groff string for ELEMENT.
+
+INFO is a plist holding contextual information. If there's no
+caption nor label, return the empty string.
+
+For non-floats, see `org-groff--wrap-label'."
+ (let ((main (org-export-get-caption element))
+ (short (org-export-get-caption element t))
+ (label (org-element-property :name element)))
+ (cond ((and (not main) (not label)) "")
+ ((not main) (format "\\fI%s\\fP" label))
+ ;; Option caption format with short name.
+ (short (format "%s\n.br\n - %s\n"
+ (org-export-data short info)
+ (org-export-data main info)))
+ ;; Standard caption format.
+ (t (format "\\fR%s\\fP" (org-export-data main info))))))
+
+(defun org-groff--wrap-label (element output)
"Wrap label associated to ELEMENT around OUTPUT, if appropriate.
This function shouldn't be used for floats. See
-`org-e-groff--caption/label-string'."
+`org-groff--caption/label-string'."
(let ((label (org-element-property :name element)))
(if (or (not output) (not label) (string= output "") (string= label ""))
output
(concat (format "%s\n.br\n" label) output))))
-(defun org-e-groff--text-markup (text markup)
+(defun org-groff--text-markup (text markup)
"Format TEXT depending on MARKUP text markup.
-See `org-e-groff-text-markup-alist' for details."
- (let ((fmt (cdr (assq markup org-e-groff-text-markup-alist))))
+See `org-groff-text-markup-alist' for details."
+ (let ((fmt (cdr (assq markup org-groff-text-markup-alist))))
(cond
;; No format string: Return raw text.
((not fmt) text)
@@ -607,10 +549,10 @@ See `org-e-groff-text-markup-alist' for details."
(t (format fmt text)))))
-(defun org-e-groff--get-tagged-content (tag info)
- (cdr (assoc tag org-e-groff-special-content)))
+(defun org-groff--get-tagged-content (tag info)
+ (cdr (assoc tag org-groff-special-content)))
-(defun org-e-groff--mt-head (title contents attr info)
+(defun org-groff--mt-head (title contents attr info)
(concat
;; 1. Insert Organization
@@ -618,7 +560,7 @@ See `org-e-groff-text-markup-alist' for details."
(cond
((stringp firm-option)
(format ".AF \"%s\" \n" firm-option))
- (t (format ".AF \"%s\" \n" (or org-e-groff-organization "")))))
+ (t (format ".AF \"%s\" \n" (or org-groff-organization "")))))
;; 2. Title
(let ((subtitle1 (plist-get attr :subtitle1))
@@ -647,9 +589,9 @@ See `org-e-groff-text-markup-alist' for details."
(and auth (org-export-data auth info)))))
(email (and (plist-get info :with-email)
(org-export-data (plist-get info :email) info)))
- (from-data (org-e-groff--get-tagged-content "FROM" info))
+ (from-data (org-groff--get-tagged-content "FROM" info))
- (to-data (org-e-groff--get-tagged-content "TO" info)))
+ (to-data (org-groff--get-tagged-content "TO" info)))
(cond
((and author from-data)
@@ -679,39 +621,44 @@ See `org-e-groff-text-markup-alist' for details."
""))
;; 5. Date.
- (let ((date (org-export-data (plist-get info :date) info)))
- (and date (format ".ND \"%s\"\n" date)))
+ (when (plist-get info :with-date)
+ (let ((date (org-export-data (org-export-get-date info) info)))
+ (and (org-string-nw-p date) (format ".ND \"%s\"\n" date))))
;;
;; If Abstract, then Populate Abstract
;;
- (let ((abstract-data (org-e-groff--get-tagged-content "ABSTRACT" info))
- (to-data (org-e-groff--get-tagged-content "TO" info)))
+ (let ((abstract-data (org-groff--get-tagged-content "ABSTRACT" info))
+ (to-data (org-groff--get-tagged-content "TO" info)))
(cond
(abstract-data
(format ".AS\n%s\n.AE\n" abstract-data))
(to-data
(format ".AS\n%s\n.AE\n" to-data))))))
-(defun org-e-groff--letter-head (title contents attr info)
+(defun org-groff--letter-head (title contents attr info)
(let ((author (and (plist-get info :with-author)
(let ((auth (plist-get info :author)))
(and auth (org-export-data auth info)))))
(email (and (plist-get info :with-email)
(org-export-data (plist-get info :email) info)))
- (from-data (org-e-groff--get-tagged-content "FROM" info))
+ (from-data (org-groff--get-tagged-content "FROM" info))
(at-item (plist-get attr :author-title))
- (to-data (org-e-groff--get-tagged-content "TO" info)))
+ (to-data (org-groff--get-tagged-content "TO" info)))
;; If FROM then get data from FROM
- (setq from-data
- (replace-regexp-in-string "\\.P\n" "" from-data))
-
- (setq to-data
- (replace-regexp-in-string "\\.P\n" "" to-data))
-
+ (if from-data
+ (setq from-data
+ (replace-regexp-in-string "\\.P\n" "" from-data))
+ (setq from-data ""))
+
+ (if to-data
+ (setq to-data
+ (replace-regexp-in-string "\\.P\n" "" to-data))
+ (setq from-data ""))
+
(concat
(cond
(from-data
@@ -729,7 +676,7 @@ See `org-e-groff-text-markup-alist' for details."
;;; Template
-(defun org-e-groff-template (contents info)
+(defun org-groff-template (contents info)
"Return complete document string after Groff conversion.
CONTENTS is the transcoded contents string. INFO is a plist
holding export options."
@@ -742,7 +689,7 @@ holding export options."
" "))))
(class (plist-get info :groff-class))
(class-options (plist-get info :groff-class-options))
- (classes (assoc class org-e-groff-classes))
+ (classes (assoc class org-groff-classes))
(classes-options (car (last classes)))
(heading-option (plist-get classes-options :heading))
(type-option (plist-get classes-options :type))
@@ -753,7 +700,7 @@ holding export options."
(document-class-string
(progn
(org-element-normalize-string
- (let* ((header (nth 1 (assoc class org-e-groff-classes)))
+ (let* ((header (nth 1 (assoc class org-groff-classes)))
(document-class-item (if (stringp header) header "")))
document-class-item)))))
@@ -781,16 +728,16 @@ holding export options."
(concat
(format ".COVER %s\n" document-class-string)
- (org-e-groff--mt-head title contents attr info)
+ (org-groff--mt-head title contents attr info)
".COVEND\n"))
((string= type-option "memo")
(concat
- (org-e-groff--mt-head title contents attr info)
+ (org-groff--mt-head title contents attr info)
document-class-string))
((string= type-option "letter")
(concat
- (org-e-groff--letter-head title contents attr info)
+ (org-groff--letter-head title contents attr info)
(let ((sa-item (plist-get attr :salutation))
(cn-item (plist-get attr :confidential))
(sj-item (plist-get attr :subject))
@@ -840,7 +787,7 @@ holding export options."
(when (string= (car item) "NS")
(replace-regexp-in-string
"\\.P\n" "" (cdr item))))
- (reverse org-e-groff-special-content) "\n")))))
+ (reverse org-groff-special-content) "\n")))))
@@ -853,90 +800,92 @@ holding export options."
;;; Bold
-(defun org-e-groff-bold (bold contents info)
+(defun org-groff-bold (bold contents info)
"Transcode BOLD from Org to Groff.
CONTENTS is the text with bold markup. INFO is a plist holding
contextual information."
- (org-e-groff--text-markup contents 'bold))
+ (org-groff--text-markup contents 'bold))
;;; Center Block
-(defun org-e-groff-center-block (center-block contents info)
+(defun org-groff-center-block (center-block contents info)
"Transcode a CENTER-BLOCK element from Org to Groff.
CONTENTS holds the contents of the center block. INFO is a plist
holding contextual information."
- (org-e-groff--wrap-label
+ (org-groff--wrap-label
center-block
(format ".DS C \n%s\n.DE" contents)))
;;; Clock
-(defun org-e-groff-clock (clock contents info)
+(defun org-groff-clock (clock contents info)
"Transcode a CLOCK element from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual
information."
(concat
(format "\\fB%s\\fP " org-clock-string)
- (format org-e-groff-inactive-timestamp-format
- (concat (org-translate-time (org-element-property :value clock))
- (let ((time (org-element-property :time clock)))
+ (format org-groff-inactive-timestamp-format
+ (concat (org-translate-time
+ (org-element-property :raw-value
+ (org-element-property :value clock)))
+ (let ((time (org-element-property :duration clock)))
(and time (format " (%s)" time)))))))
;;; Code
-(defun org-e-groff-code (code contents info)
+(defun org-groff-code (code contents info)
"Transcode a CODE object from Org to Groff.
CONTENTS is nil. INFO is a plist used as a communication
channel."
- (org-e-groff--text-markup (org-element-property :value code) 'code))
+ (org-groff--text-markup (org-element-property :value code) 'code))
;;; Comments and Comment Blocks are ignored.
;;; Drawer
-(defun org-e-groff-drawer (drawer contents info)
+(defun org-groff-drawer (drawer contents info)
"Transcode a DRAWER element from Org to Groff.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(let* ((name (org-element-property :drawer-name drawer))
- (output (if (functionp org-e-groff-format-drawer-function)
- (funcall org-e-groff-format-drawer-function
+ (output (if (functionp org-groff-format-drawer-function)
+ (funcall org-groff-format-drawer-function
name contents)
;; If there's no user defined function: simply
;; display contents of the drawer.
contents)))
- (org-e-groff--wrap-label drawer output)))
+ (org-groff--wrap-label drawer output)))
;;; Dynamic Block
-(defun org-e-groff-dynamic-block (dynamic-block contents info)
+(defun org-groff-dynamic-block (dynamic-block contents info)
"Transcode a DYNAMIC-BLOCK element from Org to Groff.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information. See `org-export-data'."
- (org-e-groff--wrap-label dynamic-block contents))
+ (org-groff--wrap-label dynamic-block contents))
;;; Entity
-(defun org-e-groff-entity (entity contents info)
+(defun org-groff-entity (entity contents info)
"Transcode an ENTITY object from Org to Groff.
CONTENTS are the definition itself. INFO is a plist holding
contextual information."
- (let ((ent (org-element-property :utf8 entity))) ent))
+ (org-element-property :utf-8 entity))
;;; Example Block
-(defun org-e-groff-example-block (example-block contents info)
+(defun org-groff-example-block (example-block contents info)
"Transcode an EXAMPLE-BLOCK element from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual
information."
- (org-e-groff--wrap-label
+ (org-groff--wrap-label
example-block
(format ".DS L\n%s\n.DE"
(org-export-format-code-default example-block info))))
;;; Export Block
-(defun org-e-groff-export-block (export-block contents info)
+(defun org-groff-export-block (export-block contents info)
"Transcode a EXPORT-BLOCK element from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual information."
(when (string= (org-element-property :type export-block) "GROFF")
@@ -944,18 +893,18 @@ CONTENTS is nil. INFO is a plist holding contextual information."
;;; Export Snippet
-(defun org-e-groff-export-snippet (export-snippet contents info)
+(defun org-groff-export-snippet (export-snippet contents info)
"Transcode a EXPORT-SNIPPET object from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual information."
- (when (eq (org-export-snippet-backend export-snippet) 'e-groff)
+ (when (eq (org-export-snippet-backend export-snippet) 'groff)
(org-element-property :value export-snippet)))
;;; Fixed Width
-(defun org-e-groff-fixed-width (fixed-width contents info)
+(defun org-groff-fixed-width (fixed-width contents info)
"Transcode a FIXED-WIDTH element from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual information."
- (org-e-groff--wrap-label
+ (org-groff--wrap-label
fixed-width
(format "\\fC\n%s\\fP"
(org-remove-indentation
@@ -968,7 +917,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
;; Footnotes are handled automatically in GROFF. Although manual
;; references can be added, not really required.
-(defun org-e-groff-footnote-reference (footnote-reference contents info)
+(defun org-groff-footnote-reference (footnote-reference contents info)
;; Changing from info to footnote-reference
(let* ((raw (org-export-get-footnote-definition footnote-reference info))
(n (org-export-get-footnote-number footnote-reference info))
@@ -976,18 +925,18 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(ref-id (plist-get (nth 1 footnote-reference) :label)))
;; It is a reference
(if (string-match "fn:rl" ref-id)
- (if (member ref-id org-e-groff-registered-references)
+ (if (member ref-id org-groff-registered-references)
(format "\\*[%s]" ref-id)
(progn
- (push ref-id org-e-groff-registered-references)
+ (push ref-id org-groff-registered-references)
(format "\\*(Rf\n.RS \"%s\" \n%s\n.RF\n" ref-id data)))
;; else it is a footnote
(format "\\u\\s-2%s\\d\\s+2\n.FS %s\n%s\n.FE\n" n n data))))
;;; Headline
-(defun org-e-groff-headline (headline contents info)
- "Transcode an HEADLINE element from Org to Groff.
+(defun org-groff-headline (headline contents info)
+ "Transcode a HEADLINE element from Org to Groff.
CONTENTS holds the contents of the headline. INFO is a plist
holding contextual information."
(let* ((class (plist-get info :groff-class))
@@ -995,7 +944,7 @@ holding contextual information."
(numberedp (org-export-numbered-headline-p headline info))
;; Section formatting will set two placeholders: one for the
;; title and the other for the contents.
- (classes (assoc class org-e-groff-classes))
+ (classes (assoc class org-groff-classes))
(classes-options (car (last classes)))
(heading-option (plist-get classes-options :heading))
(section-fmt
@@ -1021,9 +970,9 @@ holding contextual information."
(org-element-property :priority headline)))
;; Create the headline text along with a no-tag version. The
;; latter is required to remove tags from table of contents.
- (full-text (if (functionp org-e-groff-format-headline-function)
+ (full-text (if (functionp org-groff-format-headline-function)
;; User-defined formatting function.
- (funcall org-e-groff-format-headline-function
+ (funcall org-groff-format-headline-function
todo todo-type priority text tags)
;; Default formatting.
(concat
@@ -1035,9 +984,9 @@ holding contextual information."
(format " \\fC:%s:\\fP "
(mapconcat 'identity tags ":"))))))
(full-text-no-tag
- (if (functionp org-e-groff-format-headline-function)
+ (if (functionp org-groff-format-headline-function)
;; User-defined formatting function.
- (funcall org-e-groff-format-headline-function
+ (funcall org-groff-format-headline-function
todo todo-type priority text nil)
;; Default formatting.
(concat
@@ -1056,7 +1005,7 @@ holding contextual information."
(cond
;; Case 1: Special Tag
- ((member (car tags) org-e-groff-special-tags)
+ ((member (car tags) org-groff-special-tags)
(cond
((string= (car tags) "BODY") contents)
@@ -1066,11 +1015,11 @@ holding contextual information."
(format ".NS \"%s\" 1 \n%s"
(car (org-element-property :title headline))
(or contents " ")))
- org-e-groff-special-content) nil))
+ org-groff-special-content) nil))
(t
(progn
- (push (cons (car tags) contents) org-e-groff-special-content)
+ (push (cons (car tags) contents) org-groff-special-content)
nil))))
;; Case 2: This is a footnote section: ignore it.
@@ -1111,13 +1060,13 @@ holding contextual information."
;;; Inline Src Block
-(defun org-e-groff-inline-src-block (inline-src-block contents info)
+(defun org-groff-inline-src-block (inline-src-block contents info)
"Transcode an INLINE-SRC-BLOCK element from Org to Groff.
CONTENTS holds the contents of the item. INFO is a plist holding
contextual information."
(let* ((code (org-element-property :value inline-src-block)))
(cond
- (org-e-groff-source-highlight
+ (org-groff-source-highlight
(let* ((tmpdir (if (featurep 'xemacs)
temp-directory
temporary-file-directory))
@@ -1127,7 +1076,7 @@ contextual information."
(expand-file-name "reshilite" tmpdir)))
(org-lang (org-element-property :language inline-src-block))
(lst-lang (cadr (assq (intern org-lang)
- org-e-groff-source-highlight-langs)))
+ org-groff-source-highlight-langs)))
(cmd (concat (expand-file-name "source-highlight")
" -s " lst-lang
@@ -1151,7 +1100,7 @@ contextual information."
;;; Inlinetask
-(defun org-e-groff-inlinetask (inlinetask contents info)
+(defun org-groff-inlinetask (inlinetask contents info)
"Transcode an INLINETASK element from Org to Groff.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
@@ -1164,13 +1113,13 @@ holding contextual information."
(org-export-get-tags inlinetask info)))
(priority (and (plist-get info :with-priority)
(org-element-property :priority inlinetask))))
- ;; If `org-e-groff-format-inlinetask-function' is provided, call it
+ ;; If `org-groff-format-inlinetask-function' is provided, call it
;; with appropriate arguments.
- (if (functionp org-e-groff-format-inlinetask-function)
- (funcall org-e-groff-format-inlinetask-function
+ (if (functionp org-groff-format-inlinetask-function)
+ (funcall org-groff-format-inlinetask-function
todo todo-type priority title tags contents)
;; Otherwise, use a default template.
- (org-e-groff--wrap-label
+ (org-groff--wrap-label
inlinetask
(let ((full-title
(concat
@@ -1188,15 +1137,15 @@ holding contextual information."
;;; Italic
-(defun org-e-groff-italic (italic contents info)
+(defun org-groff-italic (italic contents info)
"Transcode ITALIC from Org to Groff.
CONTENTS is the text with italic markup. INFO is a plist holding
contextual information."
- (org-e-groff--text-markup contents 'italic))
+ (org-groff--text-markup contents 'italic))
;;; Item
-(defun org-e-groff-item (item contents info)
+(defun org-groff-item (item contents info)
"Transcode an ITEM element from Org to Groff.
CONTENTS holds the contents of the item. INFO is a plist holding
contextual information."
@@ -1232,7 +1181,7 @@ contextual information."
;;; Keyword
-(defun org-e-groff-keyword (keyword contents info)
+(defun org-groff-keyword (keyword contents info)
"Transcode a KEYWORD element from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual information."
(let ((key (org-element-property :key keyword))
@@ -1241,35 +1190,9 @@ CONTENTS is nil. INFO is a plist holding contextual information."
((string= key "GROFF") value)
(t nil))))
-;;; Groff Environment
-
-(defun org-e-groff-groff-environment (groff-environment contents info)
- "Transcode a GROFF-ENVIRONMENT element from Org to Groff.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((label (org-element-property :name groff-environment))
- (value (org-remove-indentation
- (org-element-property :value groff-environment))))
- (if (not (org-string-nw-p label)) value
- ;; Environment is labelled: label must be within the environment
- ;; (otherwise, a reference pointing to that element will count
- ;; the section instead).
- (with-temp-buffer
- (insert value)
- (goto-char (point-min))
- (forward-line)
- (insert (format "%s\n" label))
- (buffer-string)))))
-
-;;; Groff Fragment
-
-(defun org-e-groff-groff-fragment (groff-fragment contents info)
- "Transcode a GROFF-FRAGMENT object from Org to Groff.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (org-element-property :value groff-fragment))
-
;;; Line Break
-(defun org-e-groff-line-break (line-break contents info)
+(defun org-groff-line-break (line-break contents info)
"Transcode a LINE-BREAK object from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual information."
".br\n")
@@ -1278,7 +1201,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
;; Inline images just place a call to .PSPIC or .PS/.PE
;; and load the graph.
-(defun org-e-groff-link--inline-image (link info)
+(defun org-groff-link--inline-image (link info)
"Return Groff code for an inline image.
LINK is the link pointing to the inline image. INFO is a plist
used as a communication channel."
@@ -1286,40 +1209,35 @@ used as a communication channel."
(path (let ((raw-path (org-element-property :path link)))
(if (not (file-name-absolute-p raw-path)) raw-path
(expand-file-name raw-path))))
- (attr (read (format "(%s)"
- (mapconcat
- #'identity
- (org-element-property :attr_groff parent)
- " "))))
+ (attr (org-export-read-attribute :attr_groff link))
(placement
- (case (plist-get attr :position)
- ('center "")
- ('left "-L")
- ('right "-R")
- (t "")))
- (width (or (plist-get attr :width) ""))
- (height (or (plist-get attr :height) ""))
-
- (disable-caption (plist-get attr :disable-caption))
-
- (caption
- (org-e-groff--caption/label-string
- (org-element-property :caption parent)
- (org-element-property :name parent)
- info)))
-
+ (let ((pos (plist-get attr :position)))
+ (cond ((string= pos 'center) "")
+ ((string= pos 'left) "-L")
+ ((string= pos 'right) "-R")
+ (t ""))))
+ (width (or (plist-get attr :width) ""))
+ (height (or (plist-get attr :height) ""))
+ (caption (and (not (plist-get attr :disable-caption))
+ (org-groff--caption/label-string parent info))))
;; Now clear ATTR from any special keyword and set a default value
;; if nothing is left. Return proper string.
-
(concat
(cond
+ ((and org-groff-raster-to-ps
+ (or (string-match ".\.png$" path)
+ (string-match ".\.jpg$" path)))
+ (let ((eps-path (concat path ".eps")))
+ (shell-command (format org-groff-raster-to-ps path eps-path))
+ (format "\n.DS L F\n.PSPIC %s \"%s\" %s %s\n.DE "
+ placement eps-path width height)))
((string-match ".\.pic$" path)
(format "\n.PS\ncopy \"%s\"\n.PE" path))
(t (format "\n.DS L F\n.PSPIC %s \"%s\" %s %s\n.DE "
placement path width height)))
- (unless disable-caption (format "\n.FG \"%s\"" caption)))))
+ (and caption (format "\n.FG \"%s\"" caption)))))
-(defun org-e-groff-link (link desc info)
+(defun org-groff-link (link desc info)
"Transcode a LINK object from Org to Groff.
DESC is the description part of the link, or the empty string.
@@ -1331,7 +1249,7 @@ INFO is a plist holding contextual information. See
;; Ensure DESC really exists, or set it to nil.
(desc (and (not (string= desc "")) desc))
(imagep (org-export-inline-image-p
- link org-e-groff-inline-image-rules))
+ link org-groff-inline-image-rules))
(path (cond
((member type '("http" "https" "ftp" "mailto"))
(concat type ":" raw-path))
@@ -1345,7 +1263,7 @@ INFO is a plist holding contextual information. See
protocol)
(cond
;; Image file.
- (imagep (org-e-groff-link--inline-image link info))
+ (imagep (org-groff-link--inline-image link info))
;; import groff files
((and (string= type "file")
(string-match ".\.groff$" raw-path))
@@ -1358,7 +1276,7 @@ INFO is a plist holding contextual information. See
(format "\\fI [%s] \\fP"
(org-export-solidify-link-text path)))))
- ;; Links pointing to an headline: find destination and build
+ ;; Links pointing to a headline: find destination and build
;; appropriate referencing command.
((member type '("custom-id" "fuzzy" "id"))
(let ((destination (if (string= type "fuzzy")
@@ -1371,16 +1289,13 @@ INFO is a plist holding contextual information. See
(format "\\fI file://%s \\fP" destination)))
;; Fuzzy link points nowhere.
('nil
- (format org-e-groff-link-with-unknown-path-format
+ (format org-groff-link-with-unknown-path-format
(or desc
(org-export-data
(org-element-property :raw-link link) info))))
- ;; Fuzzy link points to an invisible target.
- (keyword nil)
- ;; LINK points to an headline. If headlines are numbered
- ;; and the link has no description, display headline's
- ;; number. Otherwise, display description or headline's
- ;; title.
+ ;; LINK points to a headline. If headlines are numbered and
+ ;; the link has no description, display headline's number.
+ ;; Otherwise, display description or headline's title.
(headline
(let ((label ""))
(if (and (plist-get info :section-numbers) (not desc))
@@ -1399,19 +1314,11 @@ INFO is a plist holding contextual information. See
;; External link without a description part.
(path (format "\\fI%s\\fP" path))
;; No path, only description. Try to do something useful.
- (t (format org-e-groff-link-with-unknown-path-format desc)))))
-
-;;; Macro
-
-(defun org-e-groff-macro (macro contents info)
- "Transcode a MACRO element from Org to Groff.
-CONTENTS is nil. INFO is a plist holding contextual information."
- ;; Use available tools.
- (org-export-expand-macro macro info))
+ (t (format org-groff-link-with-unknown-path-format desc)))))
;;; Paragraph
-(defun org-e-groff-paragraph (paragraph contents info)
+(defun org-groff-paragraph (paragraph contents info)
"Transcode a PARAGRAPH element from Org to Groff.
CONTENTS is the contents of the paragraph, as a string. INFO is
the plist used as a communication channel."
@@ -1421,7 +1328,7 @@ the plist used as a communication channel."
(fixed-paragraph "")
(class (plist-get info :groff-class))
(class-options (plist-get info :groff-class-options))
- (classes (assoc class org-e-groff-classes))
+ (classes (assoc class org-groff-classes))
(classes-options (car (last classes)))
(paragraph-option (plist-get classes-options :paragraph)))
(cond
@@ -1440,7 +1347,7 @@ the plist used as a communication channel."
;;; Plain List
-(defun org-e-groff-plain-list (plain-list contents info)
+(defun org-groff-plain-list (plain-list contents info)
"Transcode a PLAIN-LIST element from Org to Groff.
CONTENTS is the contents of the list. INFO is a plist holding
contextual information."
@@ -1452,38 +1359,41 @@ contextual information."
((eq type 'ordered) ".AL")
((eq type 'unordered) ".BL")
((eq type 'descriptive) ".VL 2.0i"))))
- (org-e-groff--wrap-label
+ (org-groff--wrap-label
plain-list
(format "%s\n%s\n.LE" groff-type contents))))
;;; Plain Text
-(defun org-e-groff-plain-text (text info)
+(defun org-groff-plain-text (text info)
"Transcode a TEXT string from Org to Groff.
TEXT is the string to transcode. INFO is a plist holding
contextual information."
- ;; Protect
- (setq text (replace-regexp-in-string
- "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
- "$\\" text nil t 1))
- ;; Handle quotation marks
- (setq text (org-e-groff--quotation-marks text info))
+(let ((output text))
+ ;; Protect various characters.
+ (setq output (replace-regexp-in-string
+ "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
+ "$\\" output nil t 1))
+ ;; Activate smart quotes. Be sure to provide original TEXT string
+ ;; since OUTPUT may have been modified.
+ (when (plist-get info :with-smart-quotes)
+ (setq output (org-export-activate-smart-quotes output :utf-8 info text)))
;; Handle Special Characters
- (if org-e-groff-special-char
- (dolist (special-char-list org-e-groff-special-char)
- (setq text
- (replace-regexp-in-string (car special-char-list)
- (cdr special-char-list) text))))
+ (if org-groff-special-char
+ (dolist (special-char-list org-groff-special-char)
+ (setq output
+ (replace-regexp-in-string (car special-char-list)
+ (cdr special-char-list) output))))
;; Handle break preservation if required.
(when (plist-get info :preserve-breaks)
- (setq text (replace-regexp-in-string
- "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n" text)))
+ (setq output (replace-regexp-in-string
+ "\\(\\\\\\\\\\)?[ \t]*\n" ".br\n" output)))
;; Return value.
- text)
+ output))
;;; Planning
-(defun org-e-groff-planning (planning contents info)
+(defun org-groff-planning (planning contents info)
"Transcode a PLANNING element from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual
information."
@@ -1496,46 +1406,39 @@ information."
(when closed
(concat
(format "\\fR %s \\fP" org-closed-string)
- (format org-e-groff-inactive-timestamp-format
- (org-translate-time closed)))))
+ (format org-groff-inactive-timestamp-format
+ (org-translate-time
+ (org-element-property :raw-value closed))))))
(let ((deadline (org-element-property :deadline planning)))
(when deadline
(concat
(format "\\fB %s \\fP" org-deadline-string)
- (format org-e-groff-active-timestamp-format
- (org-translate-time deadline)))))
+ (format org-groff-active-timestamp-format
+ (org-translate-time
+ (org-element-property :raw-value deadline))))))
(let ((scheduled (org-element-property :scheduled planning)))
(when scheduled
(concat
(format "\\fR %s \\fP" org-scheduled-string)
- (format org-e-groff-active-timestamp-format
- (org-translate-time scheduled)))))))
+ (format org-groff-active-timestamp-format
+ (org-translate-time
+ (org-element-property :raw-value scheduled))))))))
"")
""))
-;;; Property Drawer
-
-(defun org-e-groff-property-drawer (property-drawer contents info)
- "Transcode a PROPERTY-DRAWER element from Org to Groff.
-CONTENTS is nil. INFO is a plist holding contextual
-information."
- ;; The property drawer isn't exported but we want separating blank
- ;; lines nonetheless.
- "")
-
;;; Quote Block
-(defun org-e-groff-quote-block (quote-block contents info)
+(defun org-groff-quote-block (quote-block contents info)
"Transcode a QUOTE-BLOCK element from Org to Groff.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
- (org-e-groff--wrap-label
+ (org-groff--wrap-label
quote-block
(format ".DS I\n.I\n%s\n.R\n.DE" contents)))
;;; Quote Section
-(defun org-e-groff-quote-section (quote-section contents info)
+(defun org-groff-quote-section (quote-section contents info)
"Transcode a QUOTE-SECTION element from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual information."
(let ((value (org-remove-indentation
@@ -1544,7 +1447,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
;;; Radio Target
-(defun org-e-groff-radio-target (radio-target text info)
+(defun org-groff-radio-target (radio-target text info)
"Transcode a RADIO-TARGET object from Org to Groff.
TEXT is the text of the target. INFO is a plist holding
contextual information."
@@ -1555,7 +1458,7 @@ contextual information."
;;; Section
-(defun org-e-groff-section (section contents info)
+(defun org-groff-section (section contents info)
"Transcode a SECTION element from Org to Groff.
CONTENTS holds the contents of the section. INFO is a plist
holding contextual information."
@@ -1563,86 +1466,80 @@ holding contextual information."
;;; Special Block
-(defun org-e-groff-special-block (special-block contents info)
+(defun org-groff-special-block (special-block contents info)
"Transcode a SPECIAL-BLOCK element from Org to Groff.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(let ((type (downcase (org-element-property :type special-block))))
- (org-e-groff--wrap-label
+ (org-groff--wrap-label
special-block
(format "%s\n" contents))))
;;; Src Block
-(defun org-e-groff-src-block (src-block contents info)
+(defun org-groff-src-block (src-block contents info)
"Transcode a SRC-BLOCK element from Org to Groff.
CONTENTS holds the contents of the item. INFO is a plist holding
contextual information."
(let* ((lang (org-element-property :language src-block))
- (caption (org-element-property :caption src-block))
(label (org-element-property :name src-block))
(code (org-element-property :value src-block))
(custom-env (and lang
(cadr (assq (intern lang)
- org-e-groff-custom-lang-environments))))
+ org-groff-custom-lang-environments))))
(num-start (case (org-element-property :number-lines src-block)
(continued (org-export-get-loc src-block info))
(new 0)))
(retain-labels (org-element-property :retain-labels src-block))
- (attr
- (read (format "(%s)"
- (mapconcat #'identity
- (org-element-property :attr_groff src-block)
- " "))))
- (disable-caption (plist-get attr :disable-caption)))
+ (caption (and (not (org-export-read-attribute
+ :attr_groff src-block :disable-caption))
+ (org-groff--caption/label-string src-block info))))
(cond
;; Case 1. No source fontification.
- ((not org-e-groff-source-highlight)
- (let ((caption-str (org-e-groff--caption/label-string caption label info)))
- (concat
- (format ".DS I\n\\fC%s\\fP\n.DE\n"
- (org-export-format-code-default src-block info))
- (unless disable-caption (format ".EX \"%s\" " caption-str)))))
+ ((not org-groff-source-highlight)
+ (concat
+ (format ".DS I\n\\fC%s\\fP\n.DE\n"
+ (org-export-format-code-default src-block info))
+ (and caption (format ".EX \"%s\" " caption))))
;; Case 2. Source fontification.
- (org-e-groff-source-highlight
- (let* ((tmpdir (if (featurep 'xemacs)
- temp-directory
- temporary-file-directory))
- (caption-str (org-e-groff--caption/label-string caption label info))
- (in-file (make-temp-name
- (expand-file-name "srchilite" tmpdir)))
- (out-file (make-temp-name
- (expand-file-name "reshilite" tmpdir)))
-
- (org-lang (org-element-property :language src-block))
- (lst-lang (cadr (assq (intern org-lang)
- org-e-groff-source-highlight-langs)))
-
- (cmd (concat "source-highlight"
- " -s " lst-lang
- " -f groff_mm_color "
- " -i " in-file
- " -o " out-file)))
-
- (concat
- (if lst-lang
- (let ((code-block ""))
- (with-temp-file in-file (insert code))
- (shell-command cmd)
- (setq code-block (org-file-contents out-file))
- (delete-file in-file)
- (delete-file out-file)
- (format "%s\n" code-block))
- (format ".DS I\n\\fC\\m[black]%s\\m[]\\fP\n.DE\n"
- code))
- (unless disable-caption (format ".EX \"%s\" " caption-str))))))))
+ (org-groff-source-highlight
+ (let* ((tmpdir (if (featurep 'xemacs)
+ temp-directory
+ temporary-file-directory))
+ (in-file (make-temp-name
+ (expand-file-name "srchilite" tmpdir)))
+ (out-file (make-temp-name
+ (expand-file-name "reshilite" tmpdir)))
+
+ (org-lang (org-element-property :language src-block))
+ (lst-lang (cadr (assq (intern org-lang)
+ org-groff-source-highlight-langs)))
+
+ (cmd (concat "source-highlight"
+ " -s " lst-lang
+ " -f groff_mm_color "
+ " -i " in-file
+ " -o " out-file)))
+
+ (concat
+ (if lst-lang
+ (let ((code-block ""))
+ (with-temp-file in-file (insert code))
+ (shell-command cmd)
+ (setq code-block (org-file-contents out-file))
+ (delete-file in-file)
+ (delete-file out-file)
+ (format "%s\n" code-block))
+ (format ".DS I\n\\fC\\m[black]%s\\m[]\\fP\n.DE\n"
+ code))
+ (and caption (format ".EX \"%s\" " caption))))))))
;;; Statistics Cookie
-(defun org-e-groff-statistics-cookie (statistics-cookie contents info)
+(defun org-groff-statistics-cookie (statistics-cookie contents info)
"Transcode a STATISTICS-COOKIE object from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual information."
(org-element-property :value statistics-cookie))
@@ -1650,15 +1547,15 @@ CONTENTS is nil. INFO is a plist holding contextual information."
;;; Strike-Through
-(defun org-e-groff-strike-through (strike-through contents info)
+(defun org-groff-strike-through (strike-through contents info)
"Transcode STRIKE-THROUGH from Org to Groff.
CONTENTS is the text with strike-through markup. INFO is a plist
holding contextual information."
- (org-e-groff--text-markup contents 'strike-through))
+ (org-groff--text-markup contents 'strike-through))
;;; Subscript
-(defun org-e-groff-subscript (subscript contents info)
+(defun org-groff-subscript (subscript contents info)
"Transcode a SUBSCRIPT object from Org to Groff.
CONTENTS is the contents of the object. INFO is a plist holding
contextual information."
@@ -1666,7 +1563,7 @@ contextual information."
;;; Superscript "^_%s$
-(defun org-e-groff-superscript (superscript contents info)
+(defun org-groff-superscript (superscript contents info)
"Transcode a SUPERSCRIPT object from Org to Groff.
CONTENTS is the contents of the object. INFO is a plist holding
contextual information."
@@ -1675,21 +1572,21 @@ contextual information."
;;; Table
;;
-;; `org-e-groff-table' is the entry point for table transcoding. It
+;; `org-groff-table' is the entry point for table transcoding. It
;; takes care of tables with a "verbatim" attribute. Otherwise, it
-;; delegates the job to `org-e-groff-table--org-table' function,
+;; delegates the job to `org-groff-table--org-table' function,
;; depending of the type of the table.
;;
-;; `org-e-groff-table--align-string' is a subroutine used to build
+;; `org-groff-table--align-string' is a subroutine used to build
;; alignment string for Org tables.
-(defun org-e-groff-table (table contents info)
+(defun org-groff-table (table contents info)
"Transcode a TABLE element from Org to Groff.
CONTENTS is the contents of the table. INFO is a plist holding
contextual information."
(cond
;; Case 1: verbatim table.
- ((or org-e-groff-tables-verbatim
+ ((or org-groff-tables-verbatim
(let ((attr (read (format "(%s)"
(mapconcat
#'identity
@@ -1703,44 +1600,42 @@ contextual information."
`(table nil ,@(org-element-contents table))))))
;; Case 2: Standard table.
- (t (org-e-groff-table--org-table table contents info))))
+ (t (org-groff-table--org-table table contents info))))
-(defun org-e-groff-table--align-string (divider table info)
+(defun org-groff-table--align-string (divider table info)
"Return an appropriate Groff alignment string.
TABLE is the considered table. INFO is a plist used as
a communication channel."
- (let (alignment)
- ;; Extract column groups and alignment from first (non-rule)
- ;; row.
- (org-element-map
- (org-element-map
- table 'table-row
- (lambda (row)
- (and (eq (org-element-property :type row) 'standard) row))
- info 'first-match)
- 'table-cell
- (lambda (cell)
- (let* ((borders (org-export-table-cell-borders cell info))
- (raw-width (org-export-table-cell-width cell info))
- (width-cm (when raw-width (/ raw-width 5)))
- (width (if raw-width (format "w(%dc)"
- (if (< width-cm 1) 1 width-cm)) "")))
- ;; Check left border for the first cell only.
- ;; Alignment is nil on assignment
-
- (when (and (memq 'left borders) (not alignment))
- (push "|" alignment))
- (push
- (case (org-export-table-cell-alignment cell info)
- (left (concat "l" width divider))
- (right (concat "r" width divider))
- (center (concat "c" width divider)))
- alignment)
- (when (memq 'right borders) (push "|" alignment))))
- info)
+ (let (alignment)
+ ;; Extract column groups and alignment from first (non-rule) row.
+ (org-element-map
+ (org-element-map table 'table-row
+ (lambda (row)
+ (and (eq (org-element-property :type row) 'standard) row))
+ info 'first-match)
+ 'table-cell
+ (lambda (cell)
+ (let* ((borders (org-export-table-cell-borders cell info))
+ (raw-width (org-export-table-cell-width cell info))
+ (width-cm (when raw-width (/ raw-width 5)))
+ (width (if raw-width (format "w(%dc)"
+ (if (< width-cm 1) 1 width-cm)) "")))
+ ;; Check left border for the first cell only.
+ ;; Alignment is nil on assignment
+
+ (when (and (memq 'left borders) (not alignment))
+ (push "|" alignment))
+ (push
+ (case (org-export-table-cell-alignment cell info)
+ (left (concat "l" width divider))
+ (right (concat "r" width divider))
+ (center (concat "c" width divider)))
+ alignment)
+ (when (memq 'right borders) (push "|" alignment))))
+ info)
(apply 'concat (reverse alignment))))
-(defun org-e-groff-table--org-table (table contents info)
+(defun org-groff-table--org-table (table contents info)
"Return appropriate Groff code for an Org table.
TABLE is the table type element to transcode. CONTENTS is its
@@ -1748,59 +1643,38 @@ contents, as a string. INFO is a plist used as a communication
channel.
This function assumes TABLE has `org' as its `:type' attribute."
- (let* ((label (org-element-property :name table))
- (caption (org-e-groff--caption/label-string
- (org-element-property :caption table) label info))
- (attr (read (format "(%s)"
- (mapconcat #'identity
- (org-element-property :attr_groff table)
- " "))))
+ (let* ((attr (org-export-read-attribute :attr_groff table))
+ (label (org-element-property :name table))
+ (caption (and (not (plist-get attr :disable-caption))
+ (org-groff--caption/label-string table info)))
(divider (if (plist-get attr :divider) "|" " "))
;; Determine alignment string.
- (alignment (org-e-groff-table--align-string divider table info))
+ (alignment (org-groff-table--align-string divider table info))
;; Extract others display options.
(lines (org-split-string contents "\n"))
(attr-list
- (let (result-list)
- (dolist (attr-item
- (list
- (if (plist-get attr :expand)
- "expand" nil)
-
- (case (plist-get attr :placement)
- ('center "center")
- ('left nil)
- (t
- (if org-e-groff-tables-centered
- "center" "")))
-
- (case (plist-get attr :boxtype)
- ('box "box")
- ('doublebox "doublebox")
- ('allbox "allbox")
- ('none nil)
- (t "box"))))
-
- (if (not (null attr-item))
- (add-to-list 'result-list attr-item)))
- result-list))
+ (delq nil
+ (list (and (plist-get attr :expand) "expand")
+ (let ((placement (plist-get attr :placement)))
+ (cond ((string= placement 'center) "center")
+ ((string= placement 'left) nil)
+ (t (if org-groff-tables-centered "center" ""))))
+ (or (plist-get attr :boxtype) "box"))))
(title-line (plist-get attr :title-line))
- (disable-caption (plist-get attr :disable-caption))
(long-cells (plist-get attr :long-cells))
(table-format
(concat
- (format "%s"
- (or (car attr-list) ""))
+ (or (car attr-list) "")
(or
(let (output-list)
- (when (cdr attr-list)
- (dolist (attr-item (cdr attr-list))
+ (when (cdr attr-list)
+ (dolist (attr-item (cdr attr-list))
(setq output-list (concat output-list
(format ",%s" attr-item)))))
output-list) "")))
@@ -1813,66 +1687,64 @@ This function assumes TABLE has `org' as its `:type' attribute."
;; Others.
(lines
(concat ".TS\n " table-format ";\n"
- (format "%s.\n"
- (let ((final-line ""))
- (when title-line
- (dotimes (i (length first-line))
- (setq final-line (concat final-line "cb" divider))))
-
- (setq final-line (concat final-line "\n"))
-
- (if alignment
- (setq final-line (concat final-line alignment))
- (dotimes (i (length first-line))
- (setq final-line (concat final-line "c" divider))))
- final-line))
-
- (format "%s\n.TE\n"
- (let ((final-line "")
- (long-line "")
- (lines (org-split-string contents "\n")))
-
- (dolist (line-item lines)
- (setq long-line "")
-
- (if long-cells
- (progn
- (if (string= line-item "_")
- (setq long-line (format "%s\n" line-item))
- ;; else string =
- (let ((cell-item-list (org-split-string line-item "\t")))
- (dolist (cell-item cell-item-list)
-
- (cond ((eq cell-item (car (last cell-item-list)))
- (setq long-line (concat long-line
- (format "T{\n%s\nT}\t\n" cell-item))))
- (t
- (setq long-line (concat long-line
- (format "T{\n%s\nT}\t" cell-item))))))
- long-line))
- ;; else long cells
- (setq final-line (concat final-line long-line)))
-
- (setq final-line (concat final-line line-item "\n"))))
- final-line))
-
- (if (not disable-caption)
- (format ".TB \"%s\""
- caption) ""))))))
+ (format "%s.\n"
+ (let ((final-line ""))
+ (when title-line
+ (dotimes (i (length first-line))
+ (setq final-line (concat final-line "cb" divider))))
+
+ (setq final-line (concat final-line "\n"))
+
+ (if alignment
+ (setq final-line (concat final-line alignment))
+ (dotimes (i (length first-line))
+ (setq final-line (concat final-line "c" divider))))
+ final-line))
+
+ (format "%s.TE\n"
+ (let ((final-line "")
+ (long-line "")
+ (lines (org-split-string contents "\n")))
+
+ (dolist (line-item lines)
+ (setq long-line "")
+
+ (if long-cells
+ (progn
+ (if (string= line-item "_")
+ (setq long-line (format "%s\n" line-item))
+ ;; else string =
+ (let ((cell-item-list (org-split-string line-item "\t")))
+ (dolist (cell-item cell-item-list)
+
+ (cond ((eq cell-item (car (last cell-item-list)))
+ (setq long-line (concat long-line
+ (format "T{\n%s\nT}\t\n" cell-item))))
+ (t
+ (setq long-line (concat long-line
+ (format "T{\n%s\nT}\t" cell-item))))))
+ long-line))
+ ;; else long cells
+ (setq final-line (concat final-line long-line)))
+
+ (setq final-line (concat final-line line-item "\n"))))
+ final-line))
+
+ (if caption (format ".TB \"%s\"" caption) ""))))))
;;; Table Cell
-(defun org-e-groff-table-cell (table-cell contents info)
+(defun org-groff-table-cell (table-cell contents info)
"Transcode a TABLE-CELL element from Org to Groff
CONTENTS is the cell contents. INFO is a plist used as
a communication channel."
(progn
(concat (if (and contents
- org-e-groff-table-scientific-notation
+ org-groff-table-scientific-notation
(string-match orgtbl-exp-regexp contents))
;; Use appropriate format string for scientific
;; notation.
- (format org-e-groff-table-scientific-notation
+ (format org-groff-table-scientific-notation
(match-string 1 contents)
(match-string 2 contents))
contents)
@@ -1881,7 +1753,7 @@ a communication channel."
;;; Table Row
-(defun org-e-groff-table-row (table-row contents info)
+(defun org-groff-table-row (table-row contents info)
"Transcode a TABLE-ROW element from Org to Groff
CONTENTS is the contents of the row. INFO is a plist used as
a communication channel."
@@ -1908,7 +1780,7 @@ a communication channel."
;;; Target
-(defun org-e-groff-target (target contents info)
+(defun org-groff-target (target contents info)
"Transcode a TARGET object from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual
information."
@@ -1917,37 +1789,38 @@ information."
;;; Timestamp
-(defun org-e-groff-timestamp (timestamp contents info)
+(defun org-groff-timestamp (timestamp contents info)
"Transcode a TIMESTAMP object from Org to Groff.
CONTENTS is nil. INFO is a plist holding contextual
information."
- (let ((value (org-translate-time (org-element-property :value timestamp)))
- (type (org-element-property :type timestamp)))
- (cond ((memq type '(active active-range))
- (format org-e-groff-active-timestamp-format value))
- ((memq type '(inactive inactive-range))
- (format org-e-groff-inactive-timestamp-format value))
- (t (format org-e-groff-diary-timestamp-format value)))))
+ (let ((value (org-groff-plain-text
+ (org-timestamp-translate timestamp) info)))
+ (case (org-element-property :type timestamp)
+ ((active active-range)
+ (format org-groff-active-timestamp-format value))
+ ((inactive inactive-range)
+ (format org-groff-inactive-timestamp-format value))
+ (t (format org-groff-diary-timestamp-format value)))))
;;; Underline
-(defun org-e-groff-underline (underline contents info)
+(defun org-groff-underline (underline contents info)
"Transcode UNDERLINE from Org to Groff.
CONTENTS is the text with underline markup. INFO is a plist
holding contextual information."
- (org-e-groff--text-markup contents 'underline))
+ (org-groff--text-markup contents 'underline))
;;; Verbatim
-(defun org-e-groff-verbatim (verbatim contents info)
+(defun org-groff-verbatim (verbatim contents info)
"Transcode a VERBATIM object from Org to Groff.
CONTENTS is nil. INFO is a plist used as a communication
channel."
- (org-e-groff--text-markup (org-element-property :value verbatim) 'verbatim))
+ (org-groff--text-markup (org-element-property :value verbatim) 'verbatim))
;;; Verse Block
-(defun org-e-groff-verse-block (verse-block contents info)
+(defun org-groff-verse-block (verse-block contents info)
"Transcode a VERSE-BLOCK element from Org to Groff.
CONTENTS is verse block contents. INFO is a plist holding
contextual information."
@@ -1956,8 +1829,8 @@ contextual information."
;;; Interactive functions
-(defun org-e-groff-export-to-groff
- (&optional subtreep visible-only body-only ext-plist pub-dir)
+(defun org-groff-export-to-groff
+ (&optional async subtreep visible-only body-only ext-plist)
"Export current buffer to a Groff file.
If narrowing is active in the current buffer, only export its
@@ -1965,6 +1838,10 @@ narrowed part.
If a region is active, export that region.
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.
@@ -1976,19 +1853,25 @@ EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
Return output file's name."
(interactive)
- (setq org-e-groff-registered-references nil)
- (setq org-e-groff-special-content nil)
- (let ((outfile (org-export-output-file-name ".groff" subtreep pub-dir)))
- (org-export-to-file
- 'e-groff outfile subtreep visible-only body-only ext-plist)))
-
-(defun org-e-groff-export-to-pdf
- (&optional subtreep visible-only body-only ext-plist pub-dir)
+ (let ((outfile (org-export-output-file-name ".groff" subtreep)))
+ (if async
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 'groff))
+ (let ((org-groff-registered-references nil)
+ (org-groff-special-content nil))
+ `(expand-file-name
+ (org-export-to-file
+ 'groff ,outfile ,subtreep ,visible-only ,body-only
+ ',ext-plist))))
+ (let ((org-groff-registered-references nil)
+ (org-groff-special-content nil))
+ (org-export-to-file
+ 'groff outfile subtreep visible-only body-only ext-plist)))))
+
+(defun org-groff-export-to-pdf
+ (&optional async subtreep visible-only body-only ext-plist)
"Export current buffer to Groff then process through to PDF.
If narrowing is active in the current buffer, only export its
@@ -1996,6 +1879,10 @@ narrowed part.
If a region is active, export that region.
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the headline properties
first.
@@ -2007,74 +1894,81 @@ EXT-PLIST, when provided, is a property list with external
parameters overriding Org default settings, but still inferior to
file-local settings.
-When optional argument PUB-DIR is set, use it as the publishing
-directory.
-
Return PDF file's name."
(interactive)
- (org-e-groff-compile
- (org-e-groff-export-to-groff
- subtreep visible-only body-only ext-plist pub-dir)))
-
-(defun org-e-groff-compile (grofffile)
+ (if async
+ (let ((outfile (org-export-output-file-name ".groff" subtreep)))
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 'groff))
+ `(expand-file-name
+ (org-groff-compile
+ (org-export-to-file
+ 'groff ,outfile ,subtreep ,visible-only ,body-only
+ ',ext-plist)))))
+ (org-groff-compile
+ (org-groff-export-to-groff
+ nil subtreep visible-only body-only ext-plist))))
+
+(defun org-groff-compile (file)
"Compile a Groff file.
-GROFFFILE is the name of the file being compiled. Processing is
-done through the command specified in `org-e-groff-pdf-process'.
+FILE is the name of the file being compiled. Processing is done
+through the command specified in `org-groff-pdf-process'.
Return PDF file name or an error if it couldn't be produced."
- (let* ((wconfig (current-window-configuration))
- (grofffile (file-truename grofffile))
- (base (file-name-sans-extension grofffile))
+ (let* ((base-name (file-name-sans-extension (file-name-nondirectory file)))
+ (full-name (file-truename file))
+ (out-dir (file-name-directory file))
+ ;; Properly set working directory for compilation.
+ (default-directory (if (file-name-absolute-p file)
+ (file-name-directory full-name)
+ default-directory))
errors)
- (message (format "Processing Groff file %s ..." grofffile))
- (unwind-protect
- (progn
- (cond
- ;; A function is provided: Apply it.
- ((functionp org-e-groff-pdf-process)
- (funcall org-e-groff-pdf-process (shell-quote-argument grofffile)))
- ;; A list is provided: Replace %b, %f and %o with appropriate
- ;; values in each command before applying it. Output is
- ;; redirected to "*Org PDF Groff Output*" buffer.
- ((consp org-e-groff-pdf-process)
- (let* ((out-dir (or (file-name-directory grofffile) "./"))
- (outbuf (get-buffer-create "*Org PDF Groff Output*")))
- (mapc
- (lambda (command)
- (shell-command
- (replace-regexp-in-string
- "%b" (shell-quote-argument base)
- (replace-regexp-in-string
- "%f" (shell-quote-argument grofffile)
- (replace-regexp-in-string
- "%o" (shell-quote-argument out-dir) command t t)
- t t) t t)
- outbuf))
- org-e-groff-pdf-process)
- ;; Collect standard errors from output buffer.
- (setq errors (org-e-groff-collect-errors outbuf))))
- (t (error "No valid command to process to PDF")))
- (let ((pdffile (concat base ".pdf")))
- ;; Check for process failure. Provide collected errors if
- ;; possible.
- (if (not (file-exists-p pdffile))
- (error (concat (format "PDF file %s wasn't produced" pdffile)
- (when errors (concat ": " errors))))
- ;; Else remove log files, when specified, and signal end of
- ;; process to user, along with any error encountered.
- (when org-e-groff-remove-logfiles
- (dolist (ext org-e-groff-logfiles-extensions)
- (let ((file (concat base "." ext)))
- (when (file-exists-p file) (delete-file file)))))
- (message (concat "Process completed"
- (if (not errors) "."
- (concat " with errors: " errors)))))
- ;; Return output file name.
- pdffile))
- (set-window-configuration wconfig))))
-
-(defun org-e-groff-collect-errors (buffer)
+ (message (format "Processing Groff file %s ..." file))
+ (save-window-excursion
+ (cond
+ ;; A function is provided: Apply it.
+ ((functionp org-groff-pdf-process)
+ (funcall org-groff-pdf-process (shell-quote-argument file)))
+ ;; A list is provided: Replace %b, %f and %o with appropriate
+ ;; values in each command before applying it. Output is
+ ;; redirected to "*Org PDF Groff Output*" buffer.
+ ((consp org-groff-pdf-process)
+ (let ((outbuf (get-buffer-create "*Org PDF Groff Output*")))
+ (mapc
+ (lambda (command)
+ (shell-command
+ (replace-regexp-in-string
+ "%b" (shell-quote-argument base-name)
+ (replace-regexp-in-string
+ "%f" (shell-quote-argument full-name)
+ (replace-regexp-in-string
+ "%o" (shell-quote-argument out-dir) command t t)
+ t t) t t)
+ outbuf))
+ org-groff-pdf-process)
+ ;; Collect standard errors from output buffer.
+ (setq errors (org-groff-collect-errors outbuf))))
+ (t (error "No valid command to process to PDF")))
+ (let ((pdffile (concat out-dir base-name ".pdf")))
+ ;; Check for process failure. Provide collected errors if
+ ;; possible.
+ (if (not (file-exists-p pdffile))
+ (error (concat (format "PDF file %s wasn't produced" pdffile)
+ (when errors (concat ": " errors))))
+ ;; Else remove log files, when specified, and signal end of
+ ;; process to user, along with any error encountered.
+ (when org-groff-remove-logfiles
+ (dolist (ext org-groff-logfiles-extensions)
+ (let ((file (concat out-dir base-name "." ext)))
+ (when (file-exists-p file) (delete-file file)))))
+ (message (concat "Process completed"
+ (if (not errors) "."
+ (concat " with errors: " errors)))))
+ ;; Return output file name.
+ pdffile))))
+
+(defun org-groff-collect-errors (buffer)
"Collect some kind of errors from \"groff\" output
BUFFER is the buffer containing output.
Return collected error types as a string, or nil if there was
@@ -2086,5 +1980,5 @@ none."
nil)))
-(provide 'org-e-groff)
-;;; org-e-groff.el ends here
+(provide 'ox-groff)
+;;; ox-groff.el ends here
diff --git a/contrib/lisp/ox-koma-letter.el b/contrib/lisp/ox-koma-letter.el
new file mode 100644
index 0000000..0be0be9
--- /dev/null
+++ b/contrib/lisp/ox-koma-letter.el
@@ -0,0 +1,371 @@
+;;; ox-koma-letter.el --- KOMA Scrlttr2 Back-End for Org Export Engine
+
+;; Copyright (C) 2007-2012 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <n.goaziou AT gmail DOT com>
+;; Alan Schmitt <alan.schmitt AT polytechnique DOT org>
+;; Keywords: org, wp, tex
+
+;; 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This library implements a KOMA Scrlttr2 back-end, derived from the
+;; LaTeX one.
+;;
+;; Depending on the desired output format, three commands are provided
+;; for export: `org-koma-letter-export-as-latex' (temporary buffer),
+;; `org-koma-letter-export-to-latex' ("tex" file) and
+;; `org-koma-letter-export-to-pdf' ("pdf" file).
+;;
+;; On top of buffer keywords supported by `latex' back-end (see
+;; `org-latex-options-alist'), this back-end introduces the following
+;; keywords: "CLOSING" (see `org-koma-letter-closing'), "FROM_ADDRESS"
+;; (see `org-koma-letter-from-address'), "LCO" (see
+;; `org-koma-letter-class-option-file'), "OPENING" (see
+;; `org-koma-letter-opening'), "PHONE_NUMBER" (see
+;; `org-koma-letter-phone-number'), "SIGNATURE" (see
+;; `org-koma-letter-signature') and "TO_ADDRESS".
+;;
+;; You will need to add an appropriate association in
+;; `org-latex-classes' in order to use the KOMA Scrlttr2 class. For
+;; example, you can use the following code:
+;;
+;; (add-to-list 'org-latex-classes
+;; '("my-letter"
+;; "\\documentclass\[%
+;; DIV=14,
+;; fontsize=12pt,
+;; parskip=half,
+;; subject=titled,
+;; backaddress=false,
+;; fromalign=left,
+;; fromemail=true,
+;; fromphone=true\]\{scrlttr2\}
+;; \[DEFAULT-PACKAGES]
+;; \[PACKAGES]
+;; \[EXTRA]"))
+;;
+;; Then, in your Org document, be sure to require the proper class
+;; with :
+;;
+;; #+LATEX_CLASS: my-letter
+
+
+;;; Code:
+
+(require 'ox-latex)
+
+
+;;; User-Configurable Variables
+
+(defgroup org-export-koma-letter nil
+ "Options for exporting to KOMA scrlttr2 class in LaTeX export."
+ :tag "Org Koma-Letter"
+ :group 'org-export)
+
+(defcustom org-koma-letter-class-option-file "NF"
+ "Letter Class Option File."
+ :group 'org-export-koma-letter
+ :type 'string)
+
+(defcustom org-koma-letter-closing "See you soon,"
+ "Koma-Letter's closing, as a string."
+ :group 'org-export-koma-letter
+ :type 'string)
+
+(defcustom org-koma-letter-from-address "Somewhere \\ Over the rainbow."
+ "Sender's address, as a string."
+ :group 'org-export-koma-letter
+ :type 'string)
+
+(defcustom org-koma-letter-opening "Dear Sir,"
+ "Letter's opening, as a string."
+ :group 'org-export-koma-letter
+ :type 'string)
+
+(defcustom org-koma-letter-phone-number "00-00-00-00"
+ "Sender's phone number, as a string."
+ :group 'org-export-koma-letter
+ :type 'string)
+
+(defcustom org-koma-letter-signature "\\usekomavar{fromname}"
+ "String used as the signature."
+ :group 'org-export-koma-letter
+ :type 'string)
+
+
+;;; Define Back-End
+
+(org-export-define-derived-backend 'koma-letter 'latex
+ :options-alist
+ '((:closing "CLOSING" nil org-koma-letter-closing)
+ (:from-address "FROM_ADDRESS" nil org-koma-letter-from-address newline)
+ (:lco "LCO" nil org-koma-letter-class-option-file)
+ (:opening "OPENING" nil org-koma-letter-opening)
+ (:phone-number "PHONE_NUMBER" nil org-koma-letter-phone-number)
+ (:signature "SIGNATURE" nil nil newline)
+ (:to-address "TO_ADDRESS" nil nil newline))
+ :translate-alist '((export-block . org-koma-letter-export-block)
+ (export-snippet . org-koma-letter-export-snippet)
+ (keyword . org-koma-letter-keyword)
+ (template . org-koma-letter-template))
+ :menu-entry
+ '(?k "Export with KOMA Scrlttr2"
+ ((?K "As LaTeX buffer" org-koma-letter-export-as-latex)
+ (?k "As LaTeX file" org-koma-letter-export-to-latex)
+ (?p "As PDF file" org-koma-letter-export-to-pdf)
+ (?O "As PDF file and open"
+ (lambda (a s v b)
+ (if a (org-koma-letter-export-to-pdf t s v b)
+ (org-open-file (org-koma-letter-export-to-pdf nil s v b))))))))
+
+
+;;; Transcode Functions
+
+;;;; Export Block
+
+(defun org-koma-letter-export-block (export-block contents info)
+ "Transcode an EXPORT-BLOCK element into KOMA Scrlttr2 code.
+CONTENTS is nil. INFO is a plist used as a communication
+channel."
+ (when (member (org-element-property :type export-block) '("KOMA-LETTER" "LATEX"))
+ (org-remove-indentation (org-element-property :value export-block))))
+
+;;;; Export Snippet
+
+(defun org-koma-letter-export-snippet (export-snippet contents info)
+ "Transcode an EXPORT-SNIPPET object into KOMA Scrlttr2 code.
+CONTENTS is nil. INFO is a plist used as a communication
+channel."
+ (when (memq (org-export-snippet-backend export-snippet) '(latex koma-letter))
+ (org-element-property :value export-snippet)))
+
+;;;; Keyword
+
+(defun org-koma-letter-keyword (keyword contents info)
+ "Transcode a KEYWORD element into KOMA Scrlttr2 code.
+CONTENTS is nil. INFO is a plist used as a communication
+channel."
+ (let ((key (org-element-property :key keyword))
+ (value (org-element-property :value keyword)))
+ ;; Handle specifically BEAMER and TOC (headlines only) keywords.
+ ;; Otherwise, fallback to `latex' back-end.
+ (if (equal key "KOMA-LETTER") value
+ (org-export-with-backend 'latex keyword contents info))))
+
+;;;; Template
+
+(defun org-koma-letter-template (contents info)
+ "Return complete document string after KOMA Scrlttr2 conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (concat
+ ;; Time-stamp.
+ (and (plist-get info :time-stamp-file)
+ (format-time-string "%% Created %Y-%m-%d %a %H:%M\n"))
+ ;; Document class and packages.
+ (let* ((class (plist-get info :latex-class))
+ (class-options (plist-get info :latex-class-options))
+ (header (nth 1 (assoc class org-latex-classes)))
+ (document-class-string
+ (and (stringp header)
+ (if (not class-options) header
+ (replace-regexp-in-string
+ "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)"
+ class-options header t nil 1)))))
+ (if (not document-class-string)
+ (user-error "Unknown LaTeX class `%s'")
+ (org-latex-guess-babel-language
+ (org-latex-guess-inputenc
+ (org-element-normalize-string
+ (org-splice-latex-header
+ document-class-string
+ org-latex-default-packages-alist ; Defined in org.el.
+ org-latex-packages-alist nil ; Defined in org.el.
+ (concat (org-element-normalize-string
+ (plist-get info :latex-header))
+ (plist-get info :latex-header-extra)))))
+ info)))
+ ;; Define "From" data.
+ (format "\\setkomavar{fromname}{%s}\n"
+ (org-export-data (plist-get info :author) info))
+ (format "\\setkomavar{fromaddress}{%s}\n" (plist-get info :from-address))
+ (format "\\setkomavar{signature}{%s}\n" (plist-get info :signature))
+ (format "\\setkomavar{fromemail}{%s}\n"
+ (org-export-data (plist-get info :email) info))
+ (format "\\setkomavar{fromphone}{%s}\n" (plist-get info :phone-number))
+ ;; Date.
+ (format "\\date{%s}\n" (org-export-data (org-export-get-date info) info))
+ ;; Letter Class Option File
+ (format "\\LoadLetterOption{%s}\n" (plist-get info :lco))
+ ;; Letter start.
+ "\\begin{document}\n\n"
+ (format "\\setkomavar{subject}{%s}\n\n"
+ (org-export-data (plist-get info :title) info))
+ (format "\\begin{letter}{%%\n%s}\n\n"
+ (or (plist-get info :to-address) "no address given"))
+ ;; Opening.
+ (format "\\opening{%s}\n\n" (plist-get info :opening))
+ ;; Letter body.
+ contents
+ ;; Closing.
+ (format "\n\\closing{%s}\n\n" (plist-get info :closing))
+ ;; Letter end.
+ "\\end{letter}\n\\end{document}"))
+
+
+
+;;; Commands
+
+;;;###autoload
+(defun org-koma-letter-export-as-latex
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer as a KOMA Scrlttr2 letter.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Export is done in a buffer named \"*Org KOMA-LETTER Export*\". It
+will be displayed if `org-export-show-temporary-export-buffer' is
+non-nil."
+ (interactive)
+ (if async
+ (org-export-async-start
+ (lambda (output)
+ (with-current-buffer (get-buffer-create "*Org KOMA-LETTER Export*")
+ (erase-buffer)
+ (insert output)
+ (goto-char (point-min))
+ (LaTeX-mode)
+ (org-export-add-to-stack (current-buffer) 'koma-letter)))
+ `(org-export-as 'koma-letter ,subtreep ,visible-only ,body-only
+ ',ext-plist))
+ (let ((outbuf (org-export-to-buffer
+ 'koma-letter "*Org KOMA-LETTER Export*"
+ subtreep visible-only body-only ext-plist)))
+ (with-current-buffer outbuf (LaTeX-mode))
+ (when org-export-show-temporary-export-buffer
+ (switch-to-buffer-other-window outbuf)))))
+
+;;;###autoload
+(defun org-koma-letter-export-to-latex
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer as a KOMA Scrlttr2 letter (tex).
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+When optional argument PUB-DIR is set, use it as the publishing
+directory.
+
+Return output file's name."
+ (interactive)
+ (let ((outfile (org-export-output-file-name ".tex" subtreep)))
+ (if async
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 'koma-letter))
+ `(expand-file-name
+ (org-export-to-file
+ 'koma-letter ,outfile ,subtreep ,visible-only ,body-only
+ ',ext-plist)))
+ (org-export-to-file
+ 'koma-letter outfile subtreep visible-only body-only ext-plist))))
+
+;;;###autoload
+(defun org-koma-letter-export-to-pdf
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer as a KOMA Scrlttr2 letter (pdf).
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"\\begin{letter}\" and \"\\end{letter}\".
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Return PDF file's name."
+ (interactive)
+ (if async
+ (let ((outfile (org-export-output-file-name ".tex" subtreep)))
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 'koma-letter))
+ `(expand-file-name
+ (org-latex-compile
+ (org-export-to-file
+ 'koma-letter ,outfile ,subtreep ,visible-only ,body-only
+ ',ext-plist)))))
+ (org-latex-compile
+ (org-koma-letter-export-to-latex
+ nil subtreep visible-only body-only ext-plist))))
+
+
+(provide 'ox-koma-letter)
+;;; ox-koma-letter.el ends here
diff --git a/contrib/lisp/ox-rss.el b/contrib/lisp/ox-rss.el
new file mode 100644
index 0000000..a45107b
--- /dev/null
+++ b/contrib/lisp/ox-rss.el
@@ -0,0 +1,410 @@
+;;; ox-rss.el --- RSS 2.0 Back-End for Org Export Engine
+
+;; Copyright (C) 2013 Bastien Guerry
+
+;; Author: Bastien Guerry <bzg at gnu dot org>
+;; Keywords: org, wp, blog, feed, rss
+
+;; This file is not yet part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library implements a RSS 2.0 back-end for Org exporter, based on
+;; the `html' back-end.
+;;
+;; It requires Emacs 24.1 at least.
+;;
+;; It provides two commands for export, depending on the desired output:
+;; `org-rss-export-as-rss' (temporary buffer) and `org-rss-export-to-rss'
+;; (as a ".xml" file).
+;;
+;; This backend understands two new option keywords:
+;;
+;; #+RSS_EXTENSION: xml
+;; #+RSS_IMAGE_URL: http://myblog.org/mypicture.jpg
+;;
+;; It uses #+HTML_LINK_HOME: to set the base url of the feed.
+;;
+;; Exporting an Org file to RSS modifies each top-level entry by adding a
+;; PUBDATE property. If `org-rss-use-entry-url-as-guid', it will also add
+;; an ID property, later used as the guid for the feed's item.
+;;
+;; You typically want to use it within a publishing project like this:
+;;
+;; (add-to-list
+;; 'org-publish-project-alist
+;; '("homepage_rss"
+;; :base-directory "~/myhomepage/"
+;; :base-extension "org"
+;; :rss-image-url "http://lumiere.ens.fr/~guerry/images/faces/15.png"
+;; :html-link-home "http://lumiere.ens.fr/~guerry/"
+;; :rss-extension "xml"
+;; :publishing-directory "/home/guerry/public_html/"
+;; :publishing-function (org-rss-publish-to-rss)
+;; :section-numbers nil
+;; :exclude ".*" ;; To exclude all files...
+;; :include ("index.org") ;; ... except index.org.
+;; :table-of-contents nil))
+;;
+;; ... then rsync /home/guerry/public_html/ with your server.
+;;
+;; By default, the permalink for a blog entry points to the headline.
+;; You can specify a different one by using the :RSS_PERMALINK:
+;; property within an entry.
+
+;;; Code:
+
+(require 'ox-html)
+(declare-function url-encode-url "url-util" (url))
+
+;;; Variables and options
+
+(defgroup org-export-rss nil
+ "Options specific to RSS export back-end."
+ :tag "Org RSS"
+ :group 'org-export
+ :version "24.4"
+ :package-version '(Org . "8.0"))
+
+(defcustom org-rss-image-url "http://orgmode.org/img/org-mode-unicorn-logo.png"
+ "The URL of the an image for the RSS feed."
+ :group 'org-export-rss
+ :type 'string)
+
+(defcustom org-rss-extension "xml"
+ "File extension for the RSS 2.0 feed."
+ :group 'org-export-rss
+ :type 'string)
+
+(defcustom org-rss-categories 'from-tags
+ "Where to extract items category information from.
+The default is to extract categories from the tags of the
+headlines. When set to another value, extract the category
+from the :CATEGORY: property of the entry."
+ :group 'org-export-rss
+ :type '(choice
+ (const :tag "From tags" from-tags)
+ (const :tag "From the category property" from-category)))
+
+(defcustom org-rss-use-entry-url-as-guid t
+ "Use the URL for the <guid> metatag?
+When nil, Org will create ids using `org-icalendar-create-uid'."
+ :group 'org-export-rss
+ :type 'boolean)
+
+;;; Define backend
+
+(org-export-define-derived-backend 'rss 'html
+ :menu-entry
+ '(?r "Export to RSS"
+ ((?R "As RSS buffer"
+ (lambda (a s v b) (org-rss-export-as-rss a s v)))
+ (?r "As RSS file" (lambda (a s v b) (org-rss-export-to-rss a s v)))
+ (?o "As RSS file and open"
+ (lambda (a s v b)
+ (if a (org-rss-export-to-rss t s v)
+ (org-open-file (org-rss-export-to-rss nil s v)))))))
+ :options-alist
+ '((:with-toc nil nil nil) ;; Never include HTML's toc
+ (:rss-extension "RSS_EXTENSION" nil org-rss-extension)
+ (:rss-image-url "RSS_IMAGE_URL" nil org-rss-image-url)
+ (:rss-categories nil nil org-rss-categories))
+ :filters-alist '((:filter-final-output . org-rss-final-function))
+ :translate-alist '((headline . org-rss-headline)
+ (comment . (lambda (&rest args) ""))
+ (comment-block . (lambda (&rest args) ""))
+ (timestamp . (lambda (&rest args) ""))
+ (plain-text . org-rss-plain-text)
+ (section . org-rss-section)
+ (template . org-rss-template)))
+
+;;; Export functions
+
+;;;###autoload
+(defun org-rss-export-as-rss (&optional async subtreep visible-only)
+ "Export current buffer to a RSS buffer.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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.
+
+Export is done in a buffer named \"*Org RSS Export*\", which will
+be displayed when `org-export-show-temporary-export-buffer' is
+non-nil."
+ (interactive)
+ (let ((file (buffer-file-name (buffer-base-buffer))))
+ (org-icalendar-create-uid file 'warn-user)
+ (org-rss-add-pubdate-property))
+ (if async
+ (org-export-async-start
+ (lambda (output)
+ (with-current-buffer (get-buffer-create "*Org RSS Export*")
+ (erase-buffer)
+ (insert output)
+ (goto-char (point-min))
+ (text-mode)
+ (org-export-add-to-stack (current-buffer) 'rss)))
+ `(org-export-as 'rss ,subtreep ,visible-only))
+ (let ((outbuf (org-export-to-buffer
+ 'rss "*Org RSS Export*" subtreep visible-only)))
+ (with-current-buffer outbuf (text-mode))
+ (when org-export-show-temporary-export-buffer
+ (switch-to-buffer-other-window outbuf)))))
+
+;;;###autoload
+(defun org-rss-export-to-rss (&optional async subtreep visible-only)
+ "Export current buffer to a RSS file.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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.
+
+Return output file's name."
+ (interactive)
+ (let ((file (buffer-file-name (buffer-base-buffer))))
+ (org-icalendar-create-uid file 'warn-user)
+ (org-rss-add-pubdate-property))
+ (let ((outfile (org-export-output-file-name
+ (concat "." org-rss-extension) subtreep)))
+ (if async
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 'rss))
+ `(expand-file-name
+ (org-export-to-file 'rss ,outfile ,subtreep ,visible-only)))
+ (org-export-to-file 'rss outfile subtreep visible-only))))
+
+;;;###autoload
+(defun org-rss-publish-to-rss (plist filename pub-dir)
+ "Publish an org file to RSS.
+
+FILENAME is the filename of the Org file to be published. PLIST
+is the property list for the given project. PUB-DIR is the
+publishing directory.
+
+Return output file name."
+ (org-publish-org-to
+ 'rss filename (concat "." org-rss-extension) plist pub-dir))
+
+;;; Main transcoding functions
+
+(defun org-rss-headline (headline contents info)
+ "Transcode HEADLINE element into RSS format.
+CONTENTS is the headline contents. INFO is a plist used as a
+communication channel."
+ (unless (or (org-element-property :footnote-section-p headline)
+ ;; Only consider first-level headlines
+ (> (org-export-get-relative-level headline info) 1))
+ (let* ((htmlext (plist-get info :html-extension))
+ (hl-number (org-export-get-headline-number headline info))
+ (hl-home (file-name-as-directory (plist-get info :html-link-home)))
+ (hl-pdir (plist-get info :publishing-directory))
+ (hl-perm (org-element-property :RSS_PERMALINK headline))
+ (anchor
+ (org-export-solidify-link-text
+ (or (org-element-property :CUSTOM_ID headline)
+ (concat "sec-" (mapconcat 'number-to-string hl-number "-")))))
+ (category (org-rss-plain-text
+ (or (org-element-property :CATEGORY headline) "") info))
+ (pubdate
+ (let ((system-time-locale "C"))
+ (format-time-string
+ "%a, %d %h %Y %H:%M:%S %z"
+ (org-time-string-to-time
+ (or (org-element-property :PUBDATE headline)
+ (error "Missing PUBDATE property"))))))
+ (title (org-element-property :raw-value headline))
+ (publink
+ (or (and hl-perm (concat (or hl-home hl-pdir) hl-perm))
+ (concat
+ (or hl-home hl-pdir)
+ (file-name-nondirectory
+ (file-name-sans-extension
+ (plist-get info :input-file))) "." htmlext "#" anchor)))
+ (guid (if org-rss-use-entry-url-as-guid
+ publink
+ (org-rss-plain-text
+ (or (org-element-property :ID headline)
+ (org-element-property :CUSTOM_ID headline)
+ publink)
+ info))))
+ (format
+ (concat
+ "<item>\n"
+ "<title>%s</title>\n"
+ "<link>%s</link>\n"
+ "<guid isPermaLink=\"false\">%s</guid>\n"
+ "<pubDate>%s</pubDate>\n"
+ (org-rss-build-categories headline info) "\n"
+ "<description><![CDATA[%s]]></description>\n"
+ "</item>\n")
+ title publink guid pubdate contents))))
+
+(defun org-rss-build-categories (headline info)
+ "Build categories for the RSS item."
+ (if (eq (plist-get info :rss-categories) 'from-tags)
+ (mapconcat
+ (lambda (c) (format "<category><![CDATA[%s]]></category>" c))
+ (org-element-property :tags headline)
+ "\n")
+ (let ((c (org-element-property :CATEGORY headline)))
+ (format "<category><![CDATA[%s]]></category>" c))))
+
+(defun org-rss-template (contents info)
+ "Return complete document string after RSS conversion.
+CONTENTS is the transcoded contents string. INFO is a plist used
+as a communication channel."
+ (concat
+ (format "<?xml version=\"1.0\" encoding=\"%s\"?>"
+ (symbol-name org-html-coding-system))
+ "\n<rss version=\"2.0\"
+ xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"
+ xmlns:wfw=\"http://wellformedweb.org/CommentAPI/\"
+ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
+ xmlns:atom=\"http://www.w3.org/2005/Atom\"
+ xmlns:sy=\"http://purl.org/rss/1.0/modules/syndication/\"
+ xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"
+ xmlns:georss=\"http://www.georss.org/georss\"
+ xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\"
+ xmlns:media=\"http://search.yahoo.com/mrss/\">"
+ "<channel>"
+ (org-rss-build-channel-info info) "\n"
+ contents
+ "</channel>\n"
+ "</rss>"))
+
+(defun org-rss-build-channel-info (info)
+ "Build the RSS channel information."
+ (let* ((system-time-locale "C")
+ (title (plist-get info :title))
+ (email (org-export-data (plist-get info :email) info))
+ (author (and (plist-get info :with-author)
+ (let ((auth (plist-get info :author)))
+ (and auth (org-export-data auth info)))))
+ (date (format-time-string "%a, %d %h %Y %H:%M:%S %z")) ;; RFC 882
+ (description (org-export-data (plist-get info :description) info))
+ (lang (plist-get info :language))
+ (keywords (plist-get info :keywords))
+ (rssext (plist-get info :rss-extension))
+ (blogurl (or (plist-get info :html-link-home)
+ (plist-get info :publishing-directory)))
+ (image (url-encode-url (plist-get info :rss-image-url)))
+ (ifile (plist-get info :input-file))
+ (publink
+ (concat (file-name-as-directory blogurl)
+ (file-name-nondirectory
+ (file-name-sans-extension ifile))
+ "." rssext)))
+ (format
+ "\n<title>%s</title>
+<atom:link href=\"%s\" rel=\"self\" type=\"application/rss+xml\" />
+<link>%s</link>
+<description><![CDATA[%s]]></description>
+<language>%s</language>
+<pubDate>%s</pubDate>
+<lastBuildDate>%s</lastBuildDate>
+<generator>%s</generator>
+<webMaster>%s (%s)</webMaster>
+<image>
+<url>%s</url>
+<title>%s</title>
+<link>%s</link>
+</image>
+"
+ title publink blogurl description lang date date
+ (concat (format "Emacs %d.%d"
+ emacs-major-version
+ emacs-minor-version)
+ " Org-mode " (org-version))
+ email author image title blogurl)))
+
+(defun org-rss-section (section contents info)
+ "Transcode SECTION element into RSS format.
+CONTENTS is the section contents. INFO is a plist used as
+a communication channel."
+ contents)
+
+(defun org-rss-timestamp (timestamp contents info)
+ "Transcode a TIMESTAMP object from Org to RSS.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (org-html-encode-plain-text
+ (org-timestamp-translate timestamp)))
+
+(defun org-rss-plain-text (contents info)
+ "Convert plain text into RSS encoded text."
+ (let (output)
+ (setq output (org-html-encode-plain-text contents)
+ output (org-export-activate-smart-quotes
+ output :html info))))
+
+;;; Filters
+
+(defun org-rss-final-function (contents backend info)
+ "Prettify the RSS output."
+ (with-temp-buffer
+ (xml-mode)
+ (insert contents)
+ (indent-region (point-min) (point-max))
+ (buffer-substring-no-properties (point-min) (point-max))))
+
+;;; Miscellaneous
+
+(defun org-rss-add-pubdate-property ()
+ "Set the PUBDATE property for top-level headlines."
+ (let (msg)
+ (org-map-entries
+ (lambda ()
+ (let* ((entry (org-element-at-point))
+ (level (org-element-property :level entry)))
+ (when (= level 1)
+ (unless (org-entry-get (point) "PUBDATE")
+ (setq msg t)
+ (org-set-property
+ "PUBDATE" (format-time-string
+ (cdr org-time-stamp-formats)))))))
+ nil nil 'comment 'archive)
+ (when msg
+ (message "Property PUBDATE added to top-level entries in %s"
+ (buffer-file-name))
+ (sit-for 2))))
+
+(provide 'ox-rss)
+
+;;; ox-rss.el ends here
diff --git a/contrib/lisp/ox-s5.el b/contrib/lisp/ox-s5.el
new file mode 100644
index 0000000..3ea77b2
--- /dev/null
+++ b/contrib/lisp/ox-s5.el
@@ -0,0 +1,445 @@
+;;; ox-s5.el --- S5 Presentation Back-End for Org Export Engine
+
+;; Copyright (C) 2011-2013 Rick Frankel
+
+;; Author: Rick Frankel <emacs at rickster dot com>
+;; Keywords: outlines, hypermedia, S5, wp
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library implements an S5 Presentation back-end for the Org
+;; generic exporter.
+
+;; Installation
+;; ------------
+;; Get the s5 scripts from
+;; http://meyerweb.com/eric/tools/s5/
+;; (Note that the default s5 version is set for using the alpha, 1.2a2.
+;; Copy the ui dir to somewhere reachable from your published presentation
+;; The default (`org-s5-ui-url') is set to "ui" (e.g., in the
+;; same directory as the html file).
+
+;; Usage
+;; -----
+;; Follow the general instructions at the above website. To generate
+;; incremental builds, you can set the HTML_CONTAINER_CLASS on an
+;; object to "incremental" to make it build. If you want an outline to
+;; build, set the :INCREMENTAL property on the parent headline.
+
+;; To test it, run:
+;;
+;; M-x org-s5-export-as-html
+;;
+;; in an Org mode buffer. See ox.el and ox-html.el for more details
+;; on how this exporter works.
+
+(require 'ox-html)
+
+(org-export-define-derived-backend 's5 'html
+ :menu-entry
+ '(?s "Export to S5 HTML Presentation"
+ ((?H "To temporary buffer" org-s5-export-as-html)
+ (?h "To file" org-s5-export-to-html)
+ (?o "To file and open"
+ (lambda (a s v b)
+ (if a (org-s5-export-to-html t s v b)
+ (org-open-file (org-s5-export-to-html nil s v b)))))))
+ :options-alist
+ '((:html-link-home "HTML_LINK_HOME" nil nil)
+ (:html-link-up "HTML_LINK_UP" nil nil)
+ (:s5-postamble "S5_POSTAMBLE" nil org-s5-postamble newline)
+ (:s5-preamble "S5_PREAMBLE" nil org-s5-preamble newline)
+ (:html-head-include-default-style "HTML_INCLUDE_DEFAULT_STYLE" nil nil)
+ (:html-head-include-scripts "HTML_INCLUDE_SCRIPTS" nil nil)
+ (:s5-version "S5_VERSION" nil org-s5-version)
+ (:s5-theme-file "S5_THEME_FILE" nil org-s5-theme-file)
+ (:s5-ui-url "S5_UI_URL" nil org-s5-ui-url)
+ (:s5-default-view "S5_DEFAULT_VIEW" nil org-s5-default-view)
+ (:s5-control-visibility "S5_CONTROL_VISIBILITY" nil
+ org-s5-control-visibility))
+ :translate-alist
+ '((headline . org-s5-headline)
+ (plain-list . org-s5-plain-list)
+ (inner-template . org-s5-inner-template)
+ (template . org-s5-template)))
+
+(defgroup org-export-s5 nil
+ "Options for exporting Org mode files to S5 HTML Presentations."
+ :tag "Org Export S5"
+ :group 'org-export-html)
+
+(defcustom org-s5-version "1.2a2"
+ "Version of s5 being used (for version metadata.) Defaults to
+s5 v2 alpha 2.
+Can be overridden with S5_VERSION."
+ :group 'org-export-s5
+ :type 'string)
+
+(defcustom org-s5-theme-file nil
+"Url to S5 theme (slides.css) file. Can be overriden with the
+S5_THEME_FILE property. If nil, defaults to
+`org-s5-ui-url'/default/slides.css. If it starts with anything but
+\"http\" or \"/\", it is used as-is. Otherwise the link in generated
+relative to `org-s5-ui-url'.
+The links for all other required stylesheets and scripts will be
+generated relative to `org-s5-ui-url'/default."
+ :group 'org-export-s5
+ :type 'string)
+
+(defcustom org-s5-ui-url "ui"
+ "Base url to directory containing S5 \"default\" subdirectory
+and the \"s5-notes.html\" file.
+Can be overriden with the S5_UI_URL property."
+ :group 'org-export-s5
+ :type 'string)
+
+(defcustom org-s5-default-view 'slideshow
+ "Setting for \"defaultView\" meta info."
+ :group 'org-export-s5
+ :type '(choice (const slideshow) (const outline)))
+
+(defcustom org-s5-control-visibility 'hidden
+ "Setting for \"controlVis\" meta info."
+ :group 'org-export-s5
+ :type '(choice (const hidden) (const visibile)))
+
+(defvar org-s5--divs
+ '((preamble "div" "header")
+ (content "div" "content")
+ (postamble "div" "footer"))
+ "Alist of the three section elements for HTML export.
+The car of each entry is one of 'preamble, 'content or 'postamble.
+The cdrs of each entry are the ELEMENT_TYPE and ID for each
+section of the exported document.
+
+If you set `org-html-container-element' to \"li\", \"ol\" will be
+uses as the content ELEMENT_TYPE, generating an XOXO format
+slideshow.
+
+Note that changing the preamble or postamble will break the
+core S5 stylesheets.")
+
+(defcustom org-s5-postamble "<h1>%a - %t</h1>"
+ "Preamble inserted into the S5 layout section.
+When set to a string, use this string as the postamble.
+
+When set to a function, apply this function and insert the
+returned string. The function takes the property list of export
+options as its only argument.
+
+Setting the S5_POSTAMBLE option -- or the :s5-postamble in publishing
+projects -- will take precedence over this variable.
+
+Note that the default css styling will break if this is set to nil
+or an empty string."
+ :group 'org-export-s5
+ :type '(choice (const :tag "No postamble" "&#x20;")
+ (string :tag "Custom formatting string")
+ (function :tag "Function (must return a string)")))
+
+(defcustom org-s5-preamble "&#x20;"
+ "Peamble inserted into the S5 layout section.
+
+When set to a string, use this string as the preamble.
+
+When set to a function, apply this function and insert the
+returned string. The function takes the property list of export
+options as its only argument.
+
+Setting S5_PREAMBLE option -- or the :s5-preamble in publishing
+projects -- will take precedence over this variable.
+
+Note that the default css styling will break if this is set to nil
+or an empty string."
+ :group 'org-export-s5
+ :type '(choice (const :tag "No preamble" "&#x20;")
+ (string :tag "Custom formatting string")
+ (function :tag "Function (must return a string)")))
+
+(defcustom org-s5-title-slide-template
+ "<h1>%t</h1>
+<h2>%a</h2>
+<h2>%e</h2>
+<h2>%d</h2>"
+ "Format template to specify title page section.
+See `org-html-postamble-format' for the valid elements which
+can be included.
+
+It will be wrapped in the element defined in the :html-container
+property, and defaults to the value of `org-html-container-element',
+and have the id \"title-slide\"."
+ :group 'org-export-s5
+ :type 'string)
+
+(defun org-s5--format-toc-headline (headline info)
+ "Return an appropriate table of contents entry for HEADLINE.
+Note that (currently) the S5 exporter does not support deep links,
+so the table of contents is not \"active\".
+INFO is a plist used as a communication channel."
+ (let* ((headline-number (org-export-get-headline-number headline info))
+ (section-number
+ (and (not (org-export-low-level-p headline info))
+ (org-export-numbered-headline-p headline info)
+ (concat (mapconcat 'number-to-string headline-number ".") ". ")))
+ (tags (and (eq (plist-get info :with-tags) t)
+ (org-export-get-tags headline info))))
+ (concat section-number
+ (org-export-data
+ (org-export-get-alt-title headline info) info)
+ (and tags "&nbsp;&nbsp;&nbsp;") (org-html--tags tags))))
+
+(defun org-s5-toc (depth info)
+ (let* ((headlines (org-export-collect-headlines info depth))
+ (toc-entries
+ (mapcar (lambda (headline)
+ (cons (org-s5--format-toc-headline headline info)
+ (org-export-get-relative-level headline info)))
+ (org-export-collect-headlines info depth))))
+ (when toc-entries
+ (concat
+ (format "<%s id='table-of-contents' class='slide'>\n"
+ (plist-get info :html-container))
+ (format "<h1>%s</h1>\n"
+ (org-html--translate "Table of Contents" info))
+ "<div id=\"text-table-of-contents\">"
+ (org-html--toc-text toc-entries)
+ "</div>\n"
+ (format "</%s>\n" (plist-get info :html-container))))))
+
+(defun org-s5--build-head (info)
+ (let* ((dir (plist-get info :s5-ui-url))
+ (theme (or (plist-get info :s5-theme-file) "default/slides.css")))
+ (mapconcat
+ 'identity
+ (list
+ "<!-- style sheet links -->"
+ (mapconcat
+ (lambda (list)
+ (format
+ (concat
+ "<link rel='stylesheet' href='%s/default/%s' type='text/css'"
+ " media='%s' id='%s' />")
+ dir (nth 0 list) (nth 1 list) (nth 2 list)))
+ (list
+ '("outline.css" "screen" "outlineStyle")
+ '("print.css" "print" "slidePrint")
+ '("opera.css" "projection" "operaFix")) "\n")
+ (format (concat
+ "<link rel='stylesheet' href='%s' type='text/css'"
+ " media='screen' id='slideProj' />")
+ (if (string-match-p "^\\(http\\|/\\)" theme) theme
+ (concat dir "/" theme)))
+ "<!-- S5 JS -->"
+ (concat
+ "<script src='" dir
+ "/default/slides.js' type='text/javascript'></script>")) "\n")))
+
+(defun org-s5--build-meta-info (info)
+ (concat
+ (org-html--build-meta-info info)
+ (format "<meta name=\"version\" content=\"S5 %s\" />\n"
+ (plist-get info :s5-version))
+ (format "<meta name='defaultView' content='%s' />\n"
+ (plist-get info :s5-default-view))
+ (format "<meta name='controlVis' content='%s' />"
+ (plist-get info :s5-control-visibility))))
+
+(defun org-s5-headline (headline contents info)
+ (let ((org-html-toplevel-hlevel 1)
+ (class (or (org-element-property :HTML_CONTAINER_CLASS headline) ""))
+ (level (org-export-get-relative-level headline info)))
+ (when (and (= 1 level) (not (string-match-p "\\<slide\\>" class)))
+ (org-element-put-property headline :HTML_CONTAINER_CLASS (concat class " slide")))
+ (org-html-headline headline contents info)))
+
+(defun org-s5-plain-list (plain-list contents info)
+ "Transcode a PLAIN-LIST element from Org to HTML.
+CONTENTS is the contents of the list. INFO is a plist holding
+contextual information.
+If a containing headline has the property :INCREMENTAL,
+then the \"incremental\" class will be added to the to the list,
+which will make the list into a \"build\"."
+ (let* ((type (org-element-property :type plain-list))
+ (tag (case type
+ (ordered "ol")
+ (unordered "ul")
+ (descriptive "dl"))))
+ (format "%s\n%s%s"
+ (format
+ "<%s class='org-%s%s'>" tag tag
+ (if (org-export-get-node-property :INCREMENTAL plain-list t)
+ " incremental" ""))
+ contents (org-html-end-plain-list type))))
+
+(defun org-s5-inner-template (contents info)
+ "Return body of document string after HTML conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (concat contents "\n"))
+
+(defun org-s5-template (contents info)
+ "Return complete document string after HTML conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (let ((org-html-divs
+ (if (equal (plist-get info :html-container) "li")
+ (append '((content "ol" "content")) org-s5--divs)
+ org-s5--divs))
+ (info (plist-put
+ (plist-put info :html-preamble (plist-get info :s5-preamble))
+ :html-postamble (plist-get info :s5-postamble))))
+ (mapconcat
+ 'identity
+ (list
+ (plist-get info :html-doctype)
+ (format "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"%s\" xml:lang=\"%s\">"
+ (plist-get info :language) (plist-get info :language))
+ "<head>"
+ (org-s5--build-meta-info info)
+ (org-s5--build-head info)
+ (org-html--build-head info)
+ (org-html--build-mathjax-config info)
+ "</head>"
+ "<body>"
+ "<div class=\"layout\">"
+ "<div id=\"controls\"><!-- no edit --></div>"
+ "<div id=\"currentSlide\"><!-- no edit --></div>"
+ (org-html--build-pre/postamble 'preamble info)
+ (org-html--build-pre/postamble 'postamble info)
+ "</div>"
+ (format "<%s id=\"%s\" class=\"presentation\">"
+ (nth 1 (assq 'content org-html-divs))
+ (nth 2 (assq 'content org-html-divs)))
+ ;; title page
+ (format "<%s id='title-slide' class='slide'>"
+ (plist-get info :html-container))
+ (format-spec org-s5-title-slide-template (org-html-format-spec info))
+ (format "</%s>" (plist-get info :html-container))
+ ;; table of contents.
+ (let ((depth (plist-get info :with-toc)))
+ (when depth (org-s5-toc depth info)))
+ contents
+ (format "</%s>" (nth 1 (assq 'content org-html-divs)))
+ "</body>"
+ "</html>\n") "\n")))
+
+(defun org-s5-export-as-html
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to an HTML buffer.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting buffer should be accessible
+through the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"<body>\" and \"</body>\" tags.
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Export is done in a buffer named \"*Org S5 Export*\", which
+will be displayed when `org-export-show-temporary-export-buffer'
+is non-nil."
+ (interactive)
+ (if async
+ (org-export-async-start
+ (lambda (output)
+ (with-current-buffer (get-buffer-create "*Org S5 Export*")
+ (erase-buffer)
+ (insert output)
+ (goto-char (point-min))
+ (nxml-mode)
+ (org-export-add-to-stack (current-buffer) 's5)))
+ `(org-export-as 's5 ,subtreep ,visible-only ,body-only ',ext-plist))
+ (let ((outbuf (org-export-to-buffer
+ 's5 "*Org S5 Export*"
+ subtreep visible-only body-only ext-plist)))
+ ;; Set major mode.
+ (with-current-buffer outbuf (nxml-mode))
+ (when org-export-show-temporary-export-buffer
+ (switch-to-buffer-other-window outbuf)))))
+
+(defun org-s5-export-to-html
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to a S5 HTML file.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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 write code
+between \"<body>\" and \"</body>\" tags.
+
+EXT-PLIST, when provided, is a property list with external
+parameters overriding Org default settings, but still inferior to
+file-local settings.
+
+Return output file's name."
+ (interactive)
+ (let* ((extension (concat "." org-html-extension))
+ (file (org-export-output-file-name extension subtreep))
+ (org-export-coding-system org-html-coding-system))
+ (if async
+ (org-export-async-start
+ (lambda (f) (org-export-add-to-stack f 's5))
+ (let ((org-export-coding-system org-html-coding-system))
+ `(expand-file-name
+ (org-export-to-file
+ 's5 ,file ,subtreep ,visible-only ,body-only ',ext-plist))))
+ (let ((org-export-coding-system org-html-coding-system))
+ (org-export-to-file
+ 's5 file subtreep visible-only body-only ext-plist)))))
+
+(defun org-s5-publish-to-html (plist filename pub-dir)
+ "Publish an org file to S5 HTML Presentation.
+
+FILENAME is the filename of the Org file to be published. PLIST
+is the property list for the given project. PUB-DIR is the
+publishing directory.
+
+Return output file name."
+ (org-publish-org-to 's5 filename ".html" plist pub-dir))
+
+(provide 'ox-s5)
+
+;;; ox-s5.el ends here
diff --git a/contrib/lisp/ox-taskjuggler.el b/contrib/lisp/ox-taskjuggler.el
new file mode 100644
index 0000000..4724ec3
--- /dev/null
+++ b/contrib/lisp/ox-taskjuggler.el
@@ -0,0 +1,904 @@
+;;; ox-taskjuggler.el --- TaskJuggler Back-End for Org Export Engine
+;;
+;; Copyright (C) 2007-2013 Free Software Foundation, Inc.
+;;
+;; Emacs Lisp Archive Entry
+;; Filename: ox-taskjuggler.el
+;; Author: Christian Egli
+;; Nicolas Goaziou <n dot goaziou at gmail dot com>
+;; Maintainer: Christian Egli
+;; Keywords: org, taskjuggler, project planning
+;; Description: Converts an Org mode buffer into a TaskJuggler project plan
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This library implements a TaskJuggler exporter for Org mode.
+;; TaskJuggler is a project planing tool that uses a text format to
+;; define projects, tasks and resources, so it is a natural fit for
+;; Org mode. It can produce all sorts of reports for tasks or
+;; resources in either HTML, CSV or PDF. TaskJuggler is implemented
+;; in Ruby and should therefore run on any platform.
+;;
+;; The exporter does not export all the nodes of a document or
+;; strictly follow the order of the nodes in the document.
+;;
+;; Instead the TaskJuggler exporter looks for a tree that defines the
+;; tasks and a optionally tree that defines the resources for this
+;; project. It then creates a TaskJuggler file based on these trees
+;; and the attributes defined in all the nodes.
+;;
+;; * Installation
+;;
+;; Put this file into your load-path and the following line into your
+;; ~/.emacs:
+;;
+;; (add-to-list 'org-export-backends 'taskjuggler)
+;;
+;; or customize `org-export-backends' variable.
+;;
+;; The interactive functions are the following:
+;;
+;; M-x `org-taskjuggler-export'
+;; M-x `org-taskjuggler-export-and-open'
+;;
+;; * Tasks
+;;
+;; Let's illustrate the usage with a small example. Create your tasks
+;; as you usually do with org-mode. Assign efforts to each task using
+;; properties (it's easiest to do this in the column view). You
+;; should end up with something similar to the example by Peter Jones
+;; in:
+;;
+;; http://www.contextualdevelopment.com/static/artifacts/articles/2008/project-planning/project-planning.org.
+;;
+;; Now mark the top node of your tasks with a tag named
+;; "taskjuggler_project" (or whatever you customized
+;; `org-taskjuggler-project-tag' to). You are now ready to export the
+;; project plan with `org-taskjuggler-export-and-open' which will
+;; export the project plan and open a Gantt chart in TaskJugglerUI.
+;;
+;; * Resources
+;;
+;; Next you can define resources and assign those to work on specific
+;; tasks. You can group your resources hierarchically. Tag the top
+;; node of the resources with "taskjuggler_resource" (or whatever you
+;; customized `org-taskjuggler-resource-tag' to). You can optionally
+;; assign an identifier (named "resource_id") to the resources (using
+;; the standard org properties commands) or you can let the exporter
+;; generate identifiers automatically (the exporter picks the first
+;; word of the headline as the identifier as long as it is unique, see
+;; the documentation of `org-taskjuggler--build-unique-id'). Using that
+;; identifier you can then allocate resources to tasks. This is again
+;; done with the "allocate" property on the tasks. Do this in column
+;; view or when on the task type
+;;
+;; C-c C-x p allocate RET <resource_id> RET
+;;
+;; Once the allocations are done you can again export to TaskJuggler
+;; and check in the Resource Allocation Graph which person is working
+;; on what task at what time.
+;;
+;; * Export of properties
+;;
+;; The exporter also takes TODO state information into consideration,
+;; i.e. if a task is marked as done it will have the corresponding
+;; attribute in TaskJuggler ("complete 100"). Also it will export any
+;; property on a task resource or resource node which is known to
+;; TaskJuggler, such as limits, vacation, shift, booking, efficiency,
+;; journalentry, rate for resources or account, start, note, duration,
+;; end, journalentry, milestone, reference, responsible, scheduling,
+;; etc for tasks.
+;;
+;; * Dependencies
+;;
+;; The exporter will handle dependencies that are defined in the tasks
+;; either with the ORDERED attribute (see TODO dependencies in the Org
+;; mode manual) or with the BLOCKER attribute (see org-depend.el) or
+;; alternatively with a depends attribute. Both the BLOCKER and the
+;; depends attribute can be either "previous-sibling" or a reference
+;; to an identifier (named "task_id") which is defined for another
+;; task in the project. BLOCKER and the depends attribute can define
+;; multiple dependencies separated by either space or comma. You can
+;; also specify optional attributes on the dependency by simply
+;; appending it. The following examples should illustrate this:
+;;
+;; * Training material
+;; :PROPERTIES:
+;; :task_id: training_material
+;; :ORDERED: t
+;; :END:
+;; ** Markup Guidelines
+;; :PROPERTIES:
+;; :Effort: 2d
+;; :END:
+;; ** Workflow Guidelines
+;; :PROPERTIES:
+;; :Effort: 2d
+;; :END:
+;; * Presentation
+;; :PROPERTIES:
+;; :Effort: 2d
+;; :BLOCKER: training_material { gapduration 1d } some_other_task
+;; :END:
+;;
+;;;; * TODO
+;; - Look at org-file-properties, org-global-properties and
+;; org-global-properties-fixed
+;; - What about property inheritance and org-property-inherit-p?
+;; - Use TYPE_TODO as an way to assign resources
+;;
+;;; Code:
+
+(eval-when-compile (require 'cl))
+
+(require 'ox)
+
+
+
+;;; User Variables
+
+(defgroup org-export-taskjuggler nil
+ "Options specific for TaskJuggler export back-end."
+ :tag "Org Export TaskJuggler"
+ :group 'org-export)
+
+(defcustom org-taskjuggler-extension ".tjp"
+ "Extension of TaskJuggler files."
+ :group 'org-export-taskjuggler
+ :type 'string)
+
+(defcustom org-taskjuggler-project-tag "taskjuggler_project"
+ "Tag marking project's tasks.
+This tag is used to find the tree containing all the tasks for
+the project."
+ :group 'org-export-taskjuggler
+ :type 'string)
+
+(defcustom org-taskjuggler-resource-tag "taskjuggler_resource"
+ "Tag marking project's resources.
+This tag is used to find the tree containing all the resources
+for the project."
+ :group 'org-export-taskjuggler
+ :type 'string)
+
+(defcustom org-taskjuggler-report-tag "taskjuggler_report"
+ "Tag marking project's reports.
+This tag is used to find the tree containing all the reports for
+the project."
+ :group 'org-export-taskjuggler
+ :type 'string)
+
+(defcustom org-taskjuggler-target-version 3.0
+ "Which version of TaskJuggler the exporter is targeting.
+By default a project plan is exported which conforms to version
+3.x of TaskJuggler. For a project plan that is compatible with
+versions of TaskJuggler older than 3.0 set this to 2.4.
+
+If you change this variable be sure to also change
+`org-taskjuggler-default-reports' as the format of reports has
+changed considerably between version 2.x and 3.x of TaskJuggler"
+ :group 'org-export-taskjuggler
+ :type 'number)
+
+(defcustom org-taskjuggler-default-project-version "1.0"
+ "Default version string for the project.
+This value can also be set with the \":VERSION:\" property
+associated to the headline defining the project."
+ :group 'org-export-taskjuggler
+ :type 'string)
+
+(defcustom org-taskjuggler-default-project-duration 280
+ "Default project duration.
+The value will be used if no start and end date have been defined
+in the root node of the task tree, i.e. the tree that has been
+marked with `org-taskjuggler-project-tag'"
+ :group 'org-export-taskjuggler
+ :type 'integer)
+
+(defcustom org-taskjuggler-default-reports
+ '("textreport report \"Plan\" {
+ formats html
+ header '== <-query attribute=\"name\"-> =='
+
+ center -8<-
+ [#Plan Plan] | [#Resource_Allocation Resource Allocation]
+ ----
+ === Plan ===
+ <[report id=\"plan\"]>
+ ----
+ === Resource Allocation ===
+ <[report id=\"resourceGraph\"]>
+ ->8-
+}
+
+# A traditional Gantt chart with a project overview.
+taskreport plan \"\" {
+ headline \"Project Plan\"
+ columns bsi, name, start, end, effort, chart
+ loadunit shortauto
+ hideresource 1
+}
+
+# A graph showing resource allocation. It identifies whether each
+# resource is under- or over-allocated for.
+resourcereport resourceGraph \"\" {
+ headline \"Resource Allocation Graph\"
+ columns no, name, effort, weekly
+ loadunit shortauto
+ hidetask ~(isleaf() & isleaf_())
+ sorttasks plan.start.up
+}")
+ "Default reports for the project.
+These are sensible default reports to give a good out-of-the-box
+result when exporting without defining any reports. If you want
+to define your own reports you can change them here or simply
+define the default reports so that they include an external
+report definition as follows:
+
+include reports.tji
+
+These default are made to work with tj3. If you are targeting
+TaskJuggler 2.4 (see `org-taskjuggler-target-version') please
+change these defaults to something like the following:
+
+taskreport \"Gantt Chart\" {
+ headline \"Project Gantt Chart\"
+ columns hierarchindex, name, start, end, effort, duration, completed, chart
+ timeformat \"%Y-%m-%d\"
+ hideresource 1
+ loadunit shortauto
+}
+
+resourcereport \"Resource Graph\" {
+ headline \"Resource Allocation Graph\"
+ columns no, name, utilization, freeload, chart
+ loadunit shortauto
+ sorttasks startup
+ hidetask ~isleaf()
+}"
+ :group 'org-export-taskjuggler
+ :type '(repeat (string :tag "Report")))
+
+(defcustom org-taskjuggler-default-global-header ""
+ "Default global header for the project.
+This goes before project declaration, and might be useful for
+early macros."
+ :group 'org-export-taskjuggler
+ :type '(string :tag "Preamble"))
+
+(defcustom org-taskjuggler-default-global-properties
+ "shift s40 \"Part time shift\" {
+ workinghours wed, thu, fri off
+}
+"
+ "Default global properties for the project.
+
+Here you typically define global properties such as shifts,
+accounts, rates, vacation, macros and flags. Any property that
+is allowed within the TaskJuggler file can be inserted. You
+could for example include another TaskJuggler file.
+
+The global properties are inserted after the project declaration
+but before any resource and task declarations."
+ :group 'org-export-taskjuggler
+ :type '(string :tag "Preamble"))
+
+(defcustom org-taskjuggler-valid-task-attributes
+ '(account start note duration endbuffer endcredit end
+ flags journalentry length limits maxend maxstart minend
+ minstart period reference responsible scheduling
+ startbuffer startcredit statusnote chargeset charge)
+ "Valid attributes for Taskjuggler tasks.
+If one of these appears as a property for a headline, it will be
+exported with the corresponding task."
+ :group 'org-export-taskjuggler)
+
+(defcustom org-taskjuggler-valid-resource-attributes
+ '(limits vacation shift booking efficiency journalentry rate
+ workinghours flags)
+ "Valid attributes for Taskjuggler resources.
+If one of these appears as a property for a headline, it will be
+exported with the corresponding resource."
+ :group 'org-export-taskjuggler)
+
+(defcustom org-taskjuggler-valid-report-attributes
+ '(headline columns definitions timeformat hideresource hidetask
+ loadunit sorttasks formats period)
+ "Valid attributes for Taskjuggler reports.
+If one of these appears as a property for a headline, it will be
+exported with the corresponding report."
+ :group 'org-export-taskjuggler)
+
+(defcustom org-taskjuggler-keep-project-as-task t
+ "Non-nil keeps the project headline as an umbrella task for all tasks.
+Setting this to nil will allow maintaining completely separated
+task buckets, while still sharing the same resources pool."
+ :group 'org-export-taskjuggler
+ :type 'boolean)
+
+
+
+;;; Hooks
+
+(defvar org-taskjuggler-final-hook nil
+ "Hook run after a TaskJuggler files has been saved.
+This hook is run with the name of the file as argument.")
+
+
+
+;;; Back-End Definition
+
+(org-export-define-backend 'taskjuggler
+ '((template . org-taskjuggler-project-plan))
+ :menu-entry
+ '(?J "Export to TaskJuggler"
+ ((?j "As TJP file" (lambda (a s v b) (org-taskjuggler-export a s v)))
+ (?o "As TJP file and open"
+ (lambda (a s v b)
+ (if a (org-taskjuggler-export a s v)
+ (org-taskjuggler-export-and-open s v))))))
+ ;; This property will be used to store unique ids in communication
+ ;; channel. Ids will be retrieved with `org-taskjuggler-get-id'.
+ :options-alist '((:taskjuggler-unique-ids nil nil nil)))
+
+
+
+;;; Unique IDs
+
+(defun org-taskjuggler-assign-task-ids (tasks info)
+ "Assign a unique ID to each task in TASKS.
+TASKS is a list of headlines. INFO is a plist used as a
+communication channel. Return value is an alist between
+headlines and their associated ID. IDs are hierarchical, which
+means they only need to be unique among the task siblings."
+ (let* (alist
+ (build-id
+ (lambda (tasks local-ids)
+ (org-element-map tasks 'headline
+ (lambda (task)
+ (let ((id (org-taskjuggler--build-unique-id task local-ids)))
+ (push id local-ids)
+ (push (cons task id) alist)
+ (funcall build-id (org-element-contents task) nil)))
+ info nil 'headline))))
+ (funcall build-id tasks nil)
+ alist))
+
+(defun org-taskjuggler-assign-resource-ids (resources info)
+ "Assign a unique ID to each resource within RESOURCES.
+RESOURCES is a list of headlines. INFO is a plist used as a
+communication channel. Return value is an alist between
+headlines and their associated ID."
+ (let (ids)
+ (org-element-map resources 'headline
+ (lambda (resource)
+ (let ((id (org-taskjuggler--build-unique-id resource ids)))
+ (push id ids)
+ (cons resource id)))
+ info)))
+
+
+
+;;; Accessors
+
+(defun org-taskjuggler-get-project (info)
+ "Return project in parse tree.
+INFO is a plist used as a communication channel. First headline
+in buffer with `org-taskjuggler-project-tag' defines the project.
+If no such task is defined, pick the first headline in buffer.
+If there is no headline at all, return nil."
+ (or (org-element-map (plist-get info :parse-tree) 'headline
+ (lambda (hl)
+ (and (member org-taskjuggler-project-tag
+ (org-export-get-tags hl info))
+ hl))
+ info t)
+ (org-element-map tree 'headline 'identity info t)))
+
+(defun org-taskjuggler-get-id (item info)
+ "Return id for task or resource ITEM.
+ITEM is a headline. INFO is a plist used as a communication
+channel. Return value is a string."
+ (cdr (assq item (plist-get info :taskjuggler-unique-ids))))
+
+(defun org-taskjuggler-get-name (item)
+ "Return name for task or resource ITEM.
+ITEM is a headline. Return value is a string."
+ ;; Quote double quotes in name.
+ (replace-regexp-in-string
+ "\"" "\\\"" (org-element-property :raw-value item) t t))
+
+(defun org-taskjuggler-get-start (item)
+ "Return start date for task or resource ITEM.
+ITEM is a headline. Return value is a string or nil if ITEM
+doesn't have any start date defined.."
+ (let ((scheduled (org-element-property :scheduled item)))
+ (and scheduled (org-timestamp-format scheduled "%Y-%02m-%02d"))))
+
+(defun org-taskjuggler-get-end (item)
+ "Return end date for task or resource ITEM.
+ITEM is a headline. Return value is a string or nil if ITEM
+doesn't have any end date defined.."
+ (let ((deadline (org-element-property :deadline item)))
+ (and deadline (org-timestamp-format deadline "%Y-%02m-%02d"))))
+
+
+
+;;; Internal Functions
+
+(defun org-taskjuggler--indent-string (s)
+ "Indent string S by 2 spaces.
+Return new string. If S is the empty string, return it."
+ (if (equal "" s) s (replace-regexp-in-string "^ *\\S-" " \\&" s)))
+
+(defun org-taskjuggler--build-attributes (item attributes)
+ "Return attributes string for task, resource or report ITEM.
+ITEM is a headline. ATTRIBUTES is a list of symbols
+representing valid attributes for ITEM."
+ (mapconcat
+ (lambda (attribute)
+ (let ((value (org-element-property
+ (intern (upcase (format ":%s" attribute)))
+ item)))
+ (and value (format "%s %s\n" attribute value))))
+ (remq nil attributes) ""))
+
+(defun org-taskjuggler--build-unique-id (item unique-ids)
+ "Return a unique id for a given task or a resource.
+ITEM is an `headline' type element representing the task or
+resource. Its id is derived from its name and made unique
+against UNIQUE-IDS. If the (downcased) first token of the
+headline is not unique try to add more (downcased) tokens of the
+headline or finally add more underscore characters (\"_\")."
+ (let ((id (org-string-nw-p (org-element-property :TASK_ID item))))
+ ;; If an id is specified, use it, as long as it's unique.
+ (if (and id (not (member id unique-ids))) id
+ (let* ((parts (org-split-string (org-element-property :raw-value item)))
+ (id (org-taskjuggler--clean-id (downcase (pop parts)))))
+ ;; Try to add more parts of the headline to make it unique.
+ (while (and (car parts) (member id unique-ids))
+ (setq id (concat id "_"
+ (org-taskjuggler--clean-id (downcase (pop parts))))))
+ ;; If it's still not unique, add "_".
+ (while (member id unique-ids)
+ (setq id (concat id "_")))
+ id))))
+
+(defun org-taskjuggler--clean-id (id)
+ "Clean and return ID to make it acceptable for TaskJuggler.
+ID is a string."
+ ;; Replace non-ascii by "_".
+ (replace-regexp-in-string
+ "[^a-zA-Z0-9_]" "_"
+ ;; Make sure id doesn't start with a number.
+ (replace-regexp-in-string "^\\([0-9]\\)" "_\\1" id)))
+
+
+
+;;; Dependencies
+
+(defun org-taskjuggler-resolve-dependencies (task info)
+ "Return a list of all tasks TASK depends on.
+TASK is a headline. INFO is a plist used as a communication
+channel."
+ (let ((deps-ids
+ ;; Get all dependencies specified in BLOCKER and DEPENDS task
+ ;; properties. Clean options from them.
+ (let ((deps (concat (org-element-property :BLOCKER task)
+ (org-element-property :DEPENDS task))))
+ (and deps
+ (org-split-string (replace-regexp-in-string "{.*?}" "" deps)
+ "[ ,]* +"))))
+ depends)
+ (when deps-ids
+ ;; Find tasks with :task_id: property matching id in DEPS-IDS.
+ ;; Add them to DEPENDS.
+ (let* ((project (org-taskjuggler-get-project info))
+ (tasks (if org-taskjuggler-keep-project-as-task project
+ (org-element-contents project))))
+ (setq depends
+ (org-element-map tasks 'headline
+ (lambda (task)
+ (let ((task-id (org-element-property :TASK_ID task)))
+ (and task-id (member task-id deps-ids) task)))
+ info)))
+ ;; Check BLOCKER and DEPENDS properties. If "previous-sibling"
+ ;; belongs to DEPS-ID, add it to DEPENDS.
+ (when (and (member-ignore-case "previous-sibling" deps-ids)
+ (not (org-export-first-sibling-p task info)))
+ (let ((prev (org-export-get-previous-element task info)))
+ (and (not (memq prev depends)) (push prev depends)))))
+ ;; Check ORDERED status of parent.
+ (let ((parent (org-export-get-parent task)))
+ (when (and parent
+ (org-element-property :ORDERED parent)
+ (not (org-export-first-sibling-p task info)))
+ (push (org-export-get-previous-element task info) depends)))
+ ;; Return dependencies.
+ depends))
+
+(defun org-taskjuggler-format-dependencies (dependencies task info)
+ "Format DEPENDENCIES to match TaskJuggler syntax.
+DEPENDENCIES is list of dependencies for TASK, as returned by
+`org-taskjuggler-resolve-depedencies'. TASK is a headline.
+INFO is a plist used as a communication channel. Return value
+doesn't include leading \"depends\"."
+ (let ((dep-str (concat (org-element-property :BLOCKER task)
+ " "
+ (org-element-property :DEPENDS task)))
+ (get-path
+ (lambda (dep)
+ ;; Return path to DEP relatively to TASK.
+ (let ((parent (org-export-get-parent task))
+ (exclamations 1)
+ (option
+ (let ((id (org-element-property :TASK_ID dep)))
+ (and id
+ (string-match (concat id " +\\({.*?}\\)") dep-str)
+ (org-match-string-no-properties 1))))
+ path)
+ ;; Compute number of exclamation marks by looking for the
+ ;; common ancestor between TASK and DEP.
+ (while (not (org-element-map parent 'headline
+ (lambda (hl) (eq hl dep))))
+ (incf exclamations)
+ (setq parent (org-export-get-parent parent)))
+ ;; Build path from DEP to PARENT.
+ (while (not (eq parent dep))
+ (push (org-taskjuggler-get-id dep info) path)
+ (setq dep (org-export-get-parent dep)))
+ ;; Return full path. Add dependency options, if any.
+ (concat (make-string exclamations ?!)
+ (mapconcat 'identity path ".")
+ (and option (concat " " option)))))))
+ ;; Return dependencies string, without the leading "depends".
+ (mapconcat (lambda (dep) (funcall get-path dep)) dependencies ", ")))
+
+
+
+;;; Translator Functions
+
+(defun org-taskjuggler-project-plan (contents info)
+ "Build TaskJuggler project plan.
+CONTENTS is ignored. INFO is a plist holding export options.
+Return complete project plan as a string in TaskJuggler syntax."
+ (let* ((tree (plist-get info :parse-tree))
+ (project (or (org-taskjuggler-get-project info)
+ (error "No project specified"))))
+ (concat
+ ;; 1. Insert header.
+ (org-element-normalize-string org-taskjuggler-default-global-header)
+ ;; 2. Insert project.
+ (org-taskjuggler--build-project project info)
+ ;; 3. Insert global properties.
+ (org-element-normalize-string org-taskjuggler-default-global-properties)
+ ;; 4. Insert resources. Provide a default one if none is
+ ;; specified.
+ (let ((main-resources
+ ;; Collect contents from various trees marked with
+ ;; `org-taskjuggler-resource-tag'. Only gather top level
+ ;; resources.
+ (apply 'append
+ (org-element-map tree 'headline
+ (lambda (hl)
+ (and (member org-taskjuggler-resource-tag
+ (org-export-get-tags hl info))
+ (org-element-map (org-element-contents hl) 'headline
+ 'identity info nil 'headline)))
+ info nil 'headline))))
+ ;; Assign a unique ID to each resource. Store it under
+ ;; `:taskjuggler-unique-ids' property in INFO.
+ (setq info
+ (plist-put info :taskjuggler-unique-ids
+ (org-taskjuggler-assign-resource-ids
+ main-resources info)))
+ (concat
+ (if main-resources
+ (mapconcat
+ (lambda (resource) (org-taskjuggler--build-resource resource info))
+ main-resources "")
+ (format "resource %s \"%s\" {\n}\n" (user-login-name) user-full-name))
+ ;; 5. Insert tasks.
+ (let ((main-tasks
+ ;; If `org-taskjuggler-keep-project-as-task' is
+ ;; non-nil, there is only one task. Otherwise, every
+ ;; direct children of PROJECT is a top level task.
+ (if org-taskjuggler-keep-project-as-task (list project)
+ (or (org-element-map (org-element-contents project) 'headline
+ 'identity info nil 'headline)
+ (error "No task specified")))))
+ ;; Assign a unique ID to each task. Add it to
+ ;; `:taskjuggler-unique-ids' property in INFO.
+ (setq info
+ (plist-put info :taskjuggler-unique-ids
+ (append
+ (org-taskjuggler-assign-task-ids main-tasks info)
+ (plist-get info :taskjuggler-unique-ids))))
+ ;; If no resource is allocated among tasks, allocate one to
+ ;; the first task.
+ (unless (org-element-map main-tasks 'headline
+ (lambda (task) (org-element-property :ALLOCATE task))
+ info t)
+ (org-element-put-property
+ (car main-tasks) :ALLOCATE
+ (or (org-taskjuggler-get-id (car main-resources) info)
+ (user-login-name))))
+ (mapconcat
+ (lambda (task) (org-taskjuggler--build-task task info))
+ main-tasks ""))
+ ;; 6. Insert reports. If no report is defined, insert default
+ ;; reports.
+ (let ((main-reports
+ ;; Collect contents from various trees marked with
+ ;; `org-taskjuggler-report-tag'. Only gather top level
+ ;; reports.
+ (apply 'append
+ (org-element-map tree 'headline
+ (lambda (hl)
+ (and (member org-taskjuggler-report-tag
+ (org-export-get-tags hl info))
+ (org-element-map (org-element-contents hl)
+ 'headline 'identity info nil 'headline)))
+ info nil 'headline))))
+ (if main-reports
+ (mapconcat
+ (lambda (report) (org-taskjuggler--build-report report info))
+ main-reports "")
+ (mapconcat 'org-element-normalize-string
+ org-taskjuggler-default-reports ""))))))))
+
+(defun org-taskjuggler--build-project (project info)
+ "Return a project declaration.
+PROJECT is a headline. INFO is a plist used as a communication
+channel. If no start date is specified, start today. If no end
+date is specified, end `org-taskjuggler-default-project-duration'
+days from now."
+ (format "project %s \"%s\" \"%s\" %s %s {\n}\n"
+ (org-taskjuggler-get-id project info)
+ (org-taskjuggler-get-name project)
+ ;; Version is obtained through :TASKJUGGLER_VERSION:
+ ;; property or `org-taskjuggler-default-project-version'.
+ (or (org-element-property :VERSION project)
+ org-taskjuggler-default-project-version)
+ (or (org-taskjuggler-get-start project)
+ (format-time-string "%Y-%m-%d"))
+ (let ((end (org-taskjuggler-get-end project)))
+ (or (and end (format "- %s" end))
+ (format "+%sd" org-taskjuggler-default-project-duration)))))
+
+(defun org-taskjuggler--build-resource (resource info)
+ "Return a resource declaration.
+
+RESOURCE is a headline. INFO is a plist used as a communication
+channel.
+
+All valid attributes from RESOURCE are inserted. If RESOURCE
+defines a property \"resource_id\" it will be used as the id for
+this resource. Otherwise it will use the ID property. If
+neither is defined a unique id will be associated to it."
+ (concat
+ ;; Opening resource.
+ (format "resource %s \"%s\" {\n"
+ (org-taskjuggler--clean-id
+ (or (org-element-property :RESOURCE_ID resource)
+ (org-element-property :ID resource)
+ (org-taskjuggler-get-id resource info)))
+ (org-taskjuggler-get-name resource))
+ ;; Add attributes.
+ (org-taskjuggler--indent-string
+ (org-taskjuggler--build-attributes
+ resource org-taskjuggler-valid-resource-attributes))
+ ;; Add inner resources.
+ (org-taskjuggler--indent-string
+ (mapconcat
+ 'identity
+ (org-element-map (org-element-contents resource) 'headline
+ (lambda (hl) (org-taskjuggler--build-resource hl info))
+ info nil 'headline)
+ ""))
+ ;; Closing resource.
+ "}\n"))
+
+(defun org-taskjuggler--build-report (report info)
+ "Return a report declaration.
+REPORT is a headline. INFO is a plist used as a communication
+channel."
+ (concat
+ ;; Opening report.
+ (format "%s \"%s\" {\n"
+ (or (org-element-property :REPORT_KIND report) "taskreport")
+ (org-taskjuggler-get-name report))
+ ;; Add attributes.
+ (org-taskjuggler--indent-string
+ (org-taskjuggler--build-attributes
+ report org-taskjuggler-valid-report-attributes))
+ ;; Add inner reports.
+ (org-taskjuggler--indent-string
+ (mapconcat
+ 'identity
+ (org-element-map (org-element-contents report) 'headline
+ (lambda (hl) (org-taskjuggler--build-report hl info))
+ info nil 'headline)
+ ""))
+ ;; Closing report.
+ "}\n"))
+
+(defun org-taskjuggler--build-task (task info)
+ "Return a task declaration.
+
+TASK is a headline. INFO is a plist used as a communication
+channel.
+
+All valid attributes from TASK are inserted. If TASK defines
+a property \"task_id\" it will be used as the id for this task.
+Otherwise it will use the ID property. If neither is defined
+a unique id will be associated to it."
+ (let* ((allocate (org-element-property :ALLOCATE task))
+ (complete
+ (if (eq (org-element-property :todo-type task) 'done) "100"
+ (org-element-property :COMPLETE task)))
+ (depends (org-taskjuggler-resolve-dependencies task info))
+ (effort (org-element-property :EFFORT task))
+ (milestone
+ (or (org-element-property :MILESTONE task)
+ (not (or (org-element-map (org-element-contents task) 'headline
+ 'identity info t) ; Has task any child?
+ effort
+ (org-element-property :LENGTH task)
+ (org-element-property :DURATION task)
+ (and (org-taskjuggler-get-start task)
+ (org-taskjuggler-get-end task))
+ (org-element-property :PERIOD task)))))
+ (priority
+ (let ((pri (org-element-property :priority task)))
+ (and pri
+ (max 1 (/ (* 1000 (- org-lowest-priority pri))
+ (- org-lowest-priority org-highest-priority)))))))
+ (concat
+ ;; Opening task.
+ (format "task %s \"%s\" {\n"
+ (org-taskjuggler-get-id task info)
+ (org-taskjuggler-get-name task))
+ ;; Add default attributes.
+ (and depends
+ (format " depends %s\n"
+ (org-taskjuggler-format-dependencies depends task info)))
+ (and allocate
+ (format " purge %s\n allocate %s\n"
+ ;; Compatibility for previous TaskJuggler versions.
+ (if (>= org-taskjuggler-target-version 3.0) "allocate"
+ "allocations")
+ allocate))
+ (and complete (format " complete %s\n" complete))
+ (and effort
+ (format " effort %s\n"
+ (let* ((minutes (org-duration-string-to-minutes effort))
+ (hours (/ minutes 60.0)))
+ (format "%.1fh" hours))))
+ (and priority (format " priority %s\n" priority))
+ (and milestone " milestone\n")
+ ;; Add other valid attributes.
+ (org-taskjuggler--indent-string
+ (org-taskjuggler--build-attributes
+ task org-taskjuggler-valid-task-attributes))
+ ;; Add inner tasks.
+ (org-taskjuggler--indent-string
+ (mapconcat 'identity
+ (org-element-map (org-element-contents task) 'headline
+ (lambda (hl) (org-taskjuggler--build-task hl info))
+ info nil 'headline)
+ ""))
+ ;; Closing task.
+ "}\n")))
+
+
+
+;;; Interactive Functions
+
+;;;###autoload
+(defun org-taskjuggler-export (&optional async subtreep visible-only)
+ "Export current buffer to a TaskJuggler file.
+
+The exporter looks for a tree with tag that matches
+`org-taskjuggler-project-tag' and takes this as the tasks for
+this project. The first node of this tree defines the project
+properties such as project name and project period.
+
+If there is a tree with tag that matches
+`org-taskjuggler-resource-tag' this tree is taken as resources
+for the project. If no resources are specified, a default
+resource is created and allocated to the project.
+
+Also the TaskJuggler project will be created with default reports
+as defined in `org-taskjuggler-default-reports'.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+A non-nil optional argument ASYNC means the process should happen
+asynchronously. The resulting file should be accessible through
+the `org-export-stack' interface.
+
+When optional argument SUBTREEP is non-nil, export 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.
+
+Return output file's name."
+ (interactive)
+ (let ((outfile
+ (org-export-output-file-name org-taskjuggler-extension subtreep)))
+ (if async
+ (org-export-async-start
+ (lambda (f)
+ (org-export-add-to-stack f 'taskjuggler)
+ (run-hook-with-args 'org-taskjuggler-final-hook f))
+ `(expand-file-name
+ (org-export-to-file 'taskjuggler ,outfile ,subtreep ,visible-only)))
+ (org-export-to-file 'taskjuggler outfile subtreep visible-only)
+ (run-hook-with-args 'org-taskjuggler-final-hook outfile)
+ outfile)))
+
+;;;###autoload
+(defun org-taskjuggler-export-and-open (&optional subtreep visible-only)
+ "Export current buffer to a TaskJuggler file and open it.
+
+The exporter looks for a tree with tag that matches
+`org-taskjuggler-project-tag' and takes this as the tasks for
+this project. The first node of this tree defines the project
+properties such as project name and project period.
+
+If there is a tree with tag that matches
+`org-taskjuggler-resource-tag' this tree is taken as resources
+for the project. If no resources are specified, a default
+resource is created and allocated to the project.
+
+Also the TaskJuggler project will be created with default reports
+as defined in `org-taskjuggler-default-reports'.
+
+If narrowing is active in the current buffer, only export its
+narrowed part.
+
+If a region is active, export that region.
+
+When optional argument SUBTREEP is non-nil, export 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.
+
+Open file with the TaskJuggler GUI."
+ (interactive)
+ (let* ((file (org-taskjuggler-export nil subtreep visible-only))
+ (process-name "TaskJugglerUI")
+ (command (concat process-name " " file)))
+ (start-process-shell-command process-name nil command)))
+
+
+(provide 'ox-taskjuggler)
+
+;; Local variables:
+;; sentence-end-double-space: t
+;; End:
+
+;;; ox-taskjuggler.el ends here
diff --git a/contrib/scripts/StartOzServer.oz b/contrib/scripts/StartOzServer.oz
index db12dec..df3ebe6 100644
--- a/contrib/scripts/StartOzServer.oz
+++ b/contrib/scripts/StartOzServer.oz
@@ -1,5 +1,5 @@
%%% *************************************************************
-%%% Copyright (C) 2009-2012 Torsten Anders (www.torsten-anders.de)
+%%% Copyright (C) 2009-2013 Torsten Anders (www.torsten-anders.de)
%%% 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 2
diff --git a/contrib/scripts/dir2org.zsh b/contrib/scripts/dir2org.zsh
index 1ea8be4..f91ff17 100755
--- a/contrib/scripts/dir2org.zsh
+++ b/contrib/scripts/dir2org.zsh
@@ -1,3 +1,5 @@
+#!/usr/bin/env zsh
+
# desc:
#
# Output an org compatible structure representing the filesystem from
diff --git a/contrib/scripts/ditaa.jar b/contrib/scripts/ditaa.jar
new file mode 100644
index 0000000..5894de4
--- /dev/null
+++ b/contrib/scripts/ditaa.jar
Binary files differ
diff --git a/contrib/scripts/org2hpda b/contrib/scripts/org2hpda
index de0b573..07f29d9 100755
--- a/contrib/scripts/org2hpda
+++ b/contrib/scripts/org2hpda
@@ -1,5 +1,5 @@
# org2hpda - a small utility to generate hipster pda style printouts from org mode
-# Copyright (C) 2007-2012 Christian Egli
+# Copyright (C) 2007-2013 Christian Egli
#
# Version: 0.6
#
diff --git a/contrib/scripts/staticmathjax/application.ini b/contrib/scripts/staticmathjax/application.ini
index d7957b0..522376d 100644
--- a/contrib/scripts/staticmathjax/application.ini
+++ b/contrib/scripts/staticmathjax/application.ini
@@ -3,7 +3,7 @@ Vendor=Jan Boecker
Name=StaticMathJax
Version=0.2
BuildID=2
-Copyright=Copyright (c) 2010 Jan Boecker
+Copyright=Copyright (c) 2010, 2013 Jan Boecker
ID=xulapp@jboecker.de
[Gecko]
diff --git a/contrib/scripts/x11idle.c b/contrib/scripts/x11idle.c
new file mode 100644
index 0000000..22cefe1
--- /dev/null
+++ b/contrib/scripts/x11idle.c
@@ -0,0 +1,28 @@
+#include <X11/extensions/scrnsaver.h>
+#include <stdio.h>
+
+/* Based on code from
+ * http://coderrr.wordpress.com/2008/04/20/getting-idle-time-in-unix/
+ *
+ * compile with 'gcc -l Xss x11idle.c -o x11idle' and copy x11idle into your
+ * path
+ */
+main() {
+ XScreenSaverInfo *info = XScreenSaverAllocInfo();
+ //open the display specified by the DISPLAY environment variable
+ Display *display = XOpenDisplay(0);
+
+ //display could be null if there is no X server running
+ if (info == NULL || display == NULL) {
+ return -1;
+ }
+
+ //X11 is running, try to retrieve info
+ if (XScreenSaverQueryInfo(display, DefaultRootWindow(display), info) == 0) {
+ return -1;
+ }
+
+ //info was retrieved successfully, print idle time
+ printf("%lu\n", info->idle);
+ return 0;
+}