├── .gitignore ├── Carton ├── LICENSE ├── README.org ├── org-pandoc-pkg.el └── ox-pandoc.el /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | -------------------------------------------------------------------------------- /Carton: -------------------------------------------------------------------------------- 1 | (source "melpa" "http://melpa.milkbox.net/packages/") 2 | 3 | (package "org-pandoc" "1.0" "Export from Org using Pandoc") 4 | 5 | (depends-on "org" "8.0") 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Rob Tillotson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | 2 | * org-pandoc 3 | 4 | This is an exporter for Org 8.0 that outputs via Pandoc, using Markdown as the intermediate format. It is mainly intended to allow the creation of e-books via Org export; while Org's own LaTeX and HTML exporters are fine for PDF/print and web, it has no native way to make EPUBs and the like. So to deal with those, we can use Pandoc to process a format that Org does know how to export. Although Pandoc supports LaTeX, Markdown is used as the intermediate format here because it seems as though Pandoc has a harder time (stack overflows, etc.) with big LaTeX documents than it does with big Markdown documents. 5 | 6 | * Usage 7 | 8 | There are only two export entry points at present: 9 | 10 | - =org-pandoc-export-as-pandoc= (C-c C-e p P) :: Exports the Pandoc-flavored Markdown to a buffer. This is probably not terribly interesting, as the only difference from the standard Markdown output is the title and author at the top of the file. 11 | - =org-pandoc-export-to-pandoc= (C-c C-e p p) :: Exports the Pandoc-flavored Markdown to a file, then postprocesses it with Pandoc. 12 | 13 | * Controlling Pandoc Postprocessing 14 | ** Variables 15 | 16 | - =org-pandoc-output-format= :: A symbol naming the output format Pandoc should produce. Defaults to ='epub=. 17 | - =org-pandoc-output-standalone= :: If =t=, adds the "-s" option to Pandoc which makes some output formats produce a single output file instead of multiple files. (Useful for HTML, irrelevant to ePub.) 18 | - =org-pandoc-extra-options= :: A string containing extra options to Pandoc. Having trouble with stack overflows? Put the options to fix it here. 19 | - =org-pandoc-epub-rights= :: A default copyright statement for ePubs. If nil (the default), a basic copyright statement will be generated. 20 | - =org-pandoc-epub-stylesheet= :: The path to a default ePub stylesheet, if any. 21 | 22 | ** In-File Options 23 | 24 | - #+PANDOC_OPTIONS :: Add command line options to the Pandoc process. 25 | - #+EPUB_RIGHTS :: Set the copyright statement for the ePub metadata. 26 | - #+EPUB_COVER :: Path to a cover image for ePub output. 27 | - #+EPUB_STYLESHEET :: Path to a stylesheet for ePub output. 28 | 29 | The standard #+TITLE, #+AUTHOR, #+DATE, #+EMAIL, #+DESCRIPTION, and #+KEYWORDS options are also supported along with whatever other export options the standard Markdown exporter accepts. The title, author, date, and email are passed to all Pandoc output formats, while description and keywords are inserted only in ePub. 30 | 31 | -------------------------------------------------------------------------------- /org-pandoc-pkg.el: -------------------------------------------------------------------------------- 1 | (define-package "org-pandoc" "1.0" 2 | "Export from Org using Pandoc") 3 | -------------------------------------------------------------------------------- /ox-pandoc.el: -------------------------------------------------------------------------------- 1 | ;;; ox-pandoc.el --- Org exporter using Pandoc 2 | 3 | ;; Copyright 2013 Rob Tillotson 4 | 5 | ;; Author: Rob Tillotson 6 | ;; Created: 2013-07-29 7 | ;; Version: 1.0 8 | ;; Package-Requires: ((org "8.0")) 9 | 10 | ;; This file is not part of GNU Emacs. 11 | 12 | ;;; License: 13 | 14 | ;; Permission is hereby granted, free of charge, to any person obtaining a copy of 15 | ;; this software and associated documentation files (the "Software"), to deal in 16 | ;; the Software without restriction, including without limitation the rights to 17 | ;; use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 18 | ;; the Software, and to permit persons to whom the Software is furnished to do so, 19 | ;; subject to the following conditions: 20 | 21 | ;; The above copyright notice and this permission notice shall be included in all 22 | ;; copies or substantial portions of the Software. 23 | 24 | ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 26 | ;; FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 27 | ;; COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 28 | ;; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 | ;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ;;; Commentary: 32 | 33 | ;; This is a pandoc exporter for Org, built upon Markdown as an 34 | ;; intermediate format, and targeted at production of e-books in ePub format. 35 | 36 | ;;; Code: 37 | 38 | (eval-when-compile (require 'cl)) 39 | (require 'ox-md) 40 | 41 | ;;; User Modifiable Variables: 42 | 43 | (defgroup org-export-pandoc nil 44 | "Options specific to Pandoc export back-end." 45 | :tag "Org Pandoc" 46 | :group 'org-export 47 | :version "24.4" 48 | :package-version '(Org . "8.0")) 49 | 50 | (defcustom org-pandoc-process-after-export t 51 | "Run pandoc to process the file after exporting it?" 52 | :group 'org-export-pandoc 53 | :type '(choice 54 | (const :tag "Yes" t) 55 | (const :tag "No" nil))) 56 | 57 | (defcustom org-pandoc-command "pandoc" 58 | "Command to run pandoc." 59 | :group 'org-export-pandoc 60 | :type 'string) 61 | 62 | (defcustom org-pandoc-extra-options "" 63 | "Extra pandoc options to use every time. 64 | For example, if you encounter stack overflows, put the options 65 | to expand the stack here." 66 | :group 'org-export-pandoc 67 | :type 'string) 68 | 69 | (defcustom org-pandoc-output-format 'epub 70 | "Default output format for pandoc conversion." 71 | :group 'org-export-pandoc 72 | :type 'symbol) 73 | 74 | (defcustom org-pandoc-output-standalone t 75 | "Should output be a single standalone file or not?" 76 | :group 'org-export-pandoc 77 | :type 'boolean) 78 | 79 | (defcustom org-pandoc-epub-rights nil 80 | "Copyright/license statement to include in EPUB metadata." 81 | :group 'org-export-pandoc 82 | :type 'string) 83 | 84 | (defcustom org-pandoc-epub-stylesheet nil 85 | "Stylesheet to apply to EPUB files." 86 | :group 'org-export-pandoc 87 | :type 'string) 88 | 89 | (defvar org-pandoc---epub-metadata nil) 90 | (defvar org-pandoc---epub-cover-filename nil) 91 | (defvar org-pandoc---epub-stylesheet-filename nil) 92 | (defvar org-pandoc---command-options nil) 93 | 94 | (org-export-define-derived-backend 'pandoc 'md 95 | :menu-entry 96 | '(?p "Export with Pandoc" 97 | ((?P "Markdown to buffer" 98 | (lambda (a s v b) (org-pandoc-export-as-pandoc a s v))) 99 | (?p "To file" 100 | (lambda (a s v b) (org-pandoc-export-to-pandoc a s v))))) 101 | :translate-alist '((template . org-pandoc-template)) 102 | :options-alist '((:epub-rights "EPUB_RIGHTS" nil org-pandoc-epub-rights t) 103 | (:epub-cover "EPUB_COVER" nil nil t) 104 | (:epub-stylesheet "EPUB_STYLESHEET" nil org-pandoc-epub-stylesheet t) 105 | (:pandoc-options "PANDOC_OPTIONS" nil org-pandoc-extra-options 'space) 106 | )) 107 | 108 | ;; Some simple XML escaping code. I'm surprised this isn't 109 | ;; already in emacs somewhere... 110 | 111 | (defvar org-pandoc-xml-escapes 112 | '(("&" . "&") 113 | ("'" . "'") 114 | ("\"" . """) 115 | ("<" . "<") 116 | (">" . ">"))) 117 | 118 | (defun org-pandoc-escape-xml (string) 119 | (mapc #'(lambda (item) 120 | (setq string 121 | (replace-regexp-in-string (car item) (cdr item) string))) 122 | org-pandoc-xml-escapes) 123 | string) 124 | 125 | (defun org-pandoc-make-copyright-string (author email) 126 | (format "Copyright %s %s%s" (format-time-string "%Y") author 127 | (if email 128 | (format " <%s>" email) 129 | ""))) 130 | 131 | (defun org-pandoc-template (contents info) 132 | (let ((title (plist-get info :title)) 133 | (author (plist-get info :author)) 134 | (email (plist-get info :email)) 135 | (description (plist-get info :description)) 136 | (keywords (plist-get info :keywords)) 137 | (date (org-export-get-date info "%Y-%m-%d")) 138 | (rights (plist-get info :epub-rights))) 139 | ;; Since the info alist isn't available after the export, build the metadata 140 | ;; now and put it in a buffer local variable. 141 | (if (or (eq org-pandoc-output-format 'epub) 142 | (eq org-pandoc-output-format 'epub3)) 143 | (let ((xml (concat 144 | (when description 145 | (format "%s\n" (org-pandoc-escape-xml description))) 146 | (format "%s\n" 147 | (org-pandoc-escape-xml (or rights 148 | (org-pandoc-make-copyright-string (org-export-data author info) (org-export-data email info))))) 149 | (when keywords 150 | (format "%s\n" (org-pandoc-escape-xml keywords)))))) 151 | (setq org-pandoc---epub-stylesheet-filename (plist-get info :epub-stylesheet)) 152 | (setq org-pandoc---epub-metadata xml) 153 | (setq org-pandoc---epub-cover-filename (plist-get info :epub-cover))) 154 | (progn 155 | (setq org-pandoc---epub-stylesheet-filename nil) 156 | (setq org-pandoc---epub-metadata nil) 157 | (setq org-pandoc---epub-cover-filename nil))) 158 | (setq org-pandoc---command-options (plist-get info :pandoc-options)) 159 | (concat (format "%% %s\n" (org-export-data title info)) 160 | (when (and (plist-get info :with-author) 161 | author) 162 | (format "%% %s\n" (org-export-data author info))) 163 | (when (plist-get info :with-date) 164 | (format "%% %s\n" (org-export-data date info))) 165 | "\n" 166 | contents))) 167 | 168 | (defun org-pandoc-export-as-pandoc (&optional async subtreep visible-only) 169 | (interactive) 170 | (if async 171 | (org-export-async-start 172 | (lambda (output) 173 | (with-current-buffer (get-buffer-create "*Org Pandoc Export*") 174 | (erase-buffer) 175 | (insert output) 176 | (goto-char (point-min)) 177 | (markdown-mode) 178 | (org-export-add-to-stack (current-buffer) 'pandoc))) 179 | `(org-export-as 'pandoc ,subtreep ,visible-only)) 180 | (let ((outbuf (org-export-to-buffer 'pandoc "*Org Pandoc Export*" subtreep visible-only))) 181 | (with-current-buffer outbuf (markdown-mode)) 182 | (when org-export-show-temporary-export-buffer 183 | (switch-to-buffer-other-window outbuf))))) 184 | 185 | (defun org-pandoc-run-pandoc (filename outfilename output-format &optional options) 186 | (let* ((args (list "-t" (symbol-name output-format) 187 | "-o" outfilename 188 | options 189 | filename)) 190 | (command (concat org-pandoc-command " " (mapconcat 'identity args " ")))) 191 | (message "Running pandoc as: %s" command) 192 | (message "Ran pandoc: %s" (shell-command-to-string command)))) 193 | 194 | (defun org-pandoc-export-to-file (&optional outfile subtreep visible-only) 195 | (let ((metadata-file (make-temp-file "org-pandoc" nil ".xml")) 196 | (pandoc-output (concat (file-name-base outfile) "." (symbol-name org-pandoc-output-format)))) 197 | (org-export-to-file 'pandoc outfile subtreep visible-only) 198 | ;; I really hate passing info back with global variables, but I don't know how 199 | ;; else to do it. Can't use a buffer local variable because the current buffer 200 | ;; is different in this function than when the export is actually running and 201 | ;; we have access to the info plist. 202 | (let ((options (concat (when org-pandoc-output-standalone " -s") 203 | (when org-pandoc---epub-cover-filename 204 | (format " --epub-cover-image=%s" org-pandoc---epub-cover-filename)) 205 | (when org-pandoc---epub-stylesheet-filename 206 | (format " --epub-stylesheet=%s" org-pandoc---epub-stylesheet-filename)) 207 | (when org-pandoc---command-options 208 | (concat " " org-pandoc---command-options))))) 209 | (when org-pandoc---epub-metadata 210 | (with-temp-file metadata-file 211 | (insert org-pandoc---epub-metadata)) 212 | (setq options (concat options " --epub-metadata=" metadata-file))) 213 | (org-pandoc-run-pandoc outfile pandoc-output org-pandoc-output-format options)) 214 | (delete-file metadata-file) 215 | )) 216 | 217 | (defun org-pandoc-export-to-pandoc (&optional async subtreep visible-only) 218 | (interactive) 219 | (let ((outfile (org-export-output-file-name ".md" subtreep))) 220 | (if async 221 | (org-export-async-start 222 | (lambda (f) (org-export-add-to-stack f 'pandoc)) 223 | `(expand-file-name 224 | (org-pandoc-export-to-file ,outfile ,subtreep ,visible-only))) 225 | (org-pandoc-export-to-file outfile subtreep visible-only)))) 226 | 227 | (provide 'ox-pandoc) 228 | --------------------------------------------------------------------------------