]> code.delx.au - gnu-emacs/blob - lisp/org/ox-md.el
Update copyright year to 2014 by running admin/update-copyright.
[gnu-emacs] / lisp / org / ox-md.el
1 ;;; ox-md.el --- Markdown Back-End for Org Export Engine
2
3 ;; Copyright (C) 2012-2014 Free Software Foundation, Inc.
4
5 ;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
6 ;; Keywords: org, wp, markdown
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;; This library implements a Markdown back-end (vanilla flavor) for
26 ;; Org exporter, based on `html' back-end. See Org manual for more
27 ;; information.
28
29 ;;; Code:
30
31 (eval-when-compile (require 'cl))
32 (require 'ox-html)
33
34
35 \f
36 ;;; User-Configurable Variables
37
38 (defgroup org-export-md nil
39 "Options specific to Markdown export back-end."
40 :tag "Org Markdown"
41 :group 'org-export
42 :version "24.4"
43 :package-version '(Org . "8.0"))
44
45 (defcustom org-md-headline-style 'atx
46 "Style used to format headlines.
47 This variable can be set to either `atx' or `setext'."
48 :group 'org-export-md
49 :type '(choice
50 (const :tag "Use \"atx\" style" atx)
51 (const :tag "Use \"Setext\" style" setext)))
52
53
54 \f
55 ;;; Define Back-End
56
57 (org-export-define-derived-backend 'md 'html
58 :export-block '("MD" "MARKDOWN")
59 :filters-alist '((:filter-parse-tree . org-md-separate-elements))
60 :menu-entry
61 '(?m "Export to Markdown"
62 ((?M "To temporary buffer"
63 (lambda (a s v b) (org-md-export-as-markdown a s v)))
64 (?m "To file" (lambda (a s v b) (org-md-export-to-markdown a s v)))
65 (?o "To file and open"
66 (lambda (a s v b)
67 (if a (org-md-export-to-markdown t s v)
68 (org-open-file (org-md-export-to-markdown nil s v)))))))
69 :translate-alist '((bold . org-md-bold)
70 (code . org-md-verbatim)
71 (comment . (lambda (&rest args) ""))
72 (comment-block . (lambda (&rest args) ""))
73 (example-block . org-md-example-block)
74 (fixed-width . org-md-example-block)
75 (footnote-definition . ignore)
76 (footnote-reference . ignore)
77 (headline . org-md-headline)
78 (horizontal-rule . org-md-horizontal-rule)
79 (inline-src-block . org-md-verbatim)
80 (italic . org-md-italic)
81 (item . org-md-item)
82 (line-break . org-md-line-break)
83 (link . org-md-link)
84 (paragraph . org-md-paragraph)
85 (plain-list . org-md-plain-list)
86 (plain-text . org-md-plain-text)
87 (quote-block . org-md-quote-block)
88 (quote-section . org-md-example-block)
89 (section . org-md-section)
90 (src-block . org-md-example-block)
91 (template . org-md-template)
92 (verbatim . org-md-verbatim)))
93
94
95 \f
96 ;;; Filters
97
98 (defun org-md-separate-elements (tree backend info)
99 "Make sure elements are separated by at least one blank line.
100
101 TREE is the parse tree being exported. BACKEND is the export
102 back-end used. INFO is a plist used as a communication channel.
103
104 Assume BACKEND is `md'."
105 (org-element-map tree org-element-all-elements
106 (lambda (elem)
107 (unless (eq (org-element-type elem) 'org-data)
108 (org-element-put-property
109 elem :post-blank
110 (let ((post-blank (org-element-property :post-blank elem)))
111 (if (not post-blank) 1 (max 1 post-blank)))))))
112 ;; Return updated tree.
113 tree)
114
115
116 \f
117 ;;; Transcode Functions
118
119 ;;;; Bold
120
121 (defun org-md-bold (bold contents info)
122 "Transcode BOLD object into Markdown format.
123 CONTENTS is the text within bold markup. INFO is a plist used as
124 a communication channel."
125 (format "**%s**" contents))
126
127
128 ;;;; Code and Verbatim
129
130 (defun org-md-verbatim (verbatim contents info)
131 "Transcode VERBATIM object into Markdown format.
132 CONTENTS is nil. INFO is a plist used as a communication
133 channel."
134 (let ((value (org-element-property :value verbatim)))
135 (format (cond ((not (string-match "`" value)) "`%s`")
136 ((or (string-match "\\``" value)
137 (string-match "`\\'" value))
138 "`` %s ``")
139 (t "``%s``"))
140 value)))
141
142
143 ;;;; Example Block and Src Block
144
145 (defun org-md-example-block (example-block contents info)
146 "Transcode EXAMPLE-BLOCK element into Markdown format.
147 CONTENTS is nil. INFO is a plist used as a communication
148 channel."
149 (replace-regexp-in-string
150 "^" " "
151 (org-remove-indentation
152 (org-element-property :value example-block))))
153
154
155 ;;;; Headline
156
157 (defun org-md-headline (headline contents info)
158 "Transcode HEADLINE element into Markdown format.
159 CONTENTS is the headline contents. INFO is a plist used as
160 a communication channel."
161 (unless (org-element-property :footnote-section-p headline)
162 (let* ((level (org-export-get-relative-level headline info))
163 (title (org-export-data (org-element-property :title headline) info))
164 (todo (and (plist-get info :with-todo-keywords)
165 (let ((todo (org-element-property :todo-keyword
166 headline)))
167 (and todo (concat (org-export-data todo info) " ")))))
168 (tags (and (plist-get info :with-tags)
169 (let ((tag-list (org-export-get-tags headline info)))
170 (and tag-list
171 (format " :%s:"
172 (mapconcat 'identity tag-list ":"))))))
173 (priority
174 (and (plist-get info :with-priority)
175 (let ((char (org-element-property :priority headline)))
176 (and char (format "[#%c] " char)))))
177 ;; Headline text without tags.
178 (heading (concat todo priority title)))
179 (cond
180 ;; Cannot create a headline. Fall-back to a list.
181 ((or (org-export-low-level-p headline info)
182 (not (memq org-md-headline-style '(atx setext)))
183 (and (eq org-md-headline-style 'atx) (> level 6))
184 (and (eq org-md-headline-style 'setext) (> level 2)))
185 (let ((bullet
186 (if (not (org-export-numbered-headline-p headline info)) "-"
187 (concat (number-to-string
188 (car (last (org-export-get-headline-number
189 headline info))))
190 "."))))
191 (concat bullet (make-string (- 4 (length bullet)) ? ) heading tags
192 "\n\n"
193 (and contents
194 (replace-regexp-in-string "^" " " contents)))))
195 ;; Use "Setext" style.
196 ((eq org-md-headline-style 'setext)
197 (concat heading tags "\n"
198 (make-string (length heading) (if (= level 1) ?= ?-))
199 "\n\n"
200 contents))
201 ;; Use "atx" style.
202 (t (concat (make-string level ?#) " " heading tags "\n\n" contents))))))
203
204
205 ;;;; Horizontal Rule
206
207 (defun org-md-horizontal-rule (horizontal-rule contents info)
208 "Transcode HORIZONTAL-RULE element into Markdown format.
209 CONTENTS is the horizontal rule contents. INFO is a plist used
210 as a communication channel."
211 "---")
212
213
214 ;;;; Italic
215
216 (defun org-md-italic (italic contents info)
217 "Transcode ITALIC object into Markdown format.
218 CONTENTS is the text within italic markup. INFO is a plist used
219 as a communication channel."
220 (format "*%s*" contents))
221
222
223 ;;;; Item
224
225 (defun org-md-item (item contents info)
226 "Transcode ITEM element into Markdown format.
227 CONTENTS is the item contents. INFO is a plist used as
228 a communication channel."
229 (let* ((type (org-element-property :type (org-export-get-parent item)))
230 (struct (org-element-property :structure item))
231 (bullet (if (not (eq type 'ordered)) "-"
232 (concat (number-to-string
233 (car (last (org-list-get-item-number
234 (org-element-property :begin item)
235 struct
236 (org-list-prevs-alist struct)
237 (org-list-parents-alist struct)))))
238 "."))))
239 (concat bullet
240 (make-string (- 4 (length bullet)) ? )
241 (case (org-element-property :checkbox item)
242 (on "[X] ")
243 (trans "[-] ")
244 (off "[ ] "))
245 (let ((tag (org-element-property :tag item)))
246 (and tag (format "**%s:** "(org-export-data tag info))))
247 (org-trim (replace-regexp-in-string "^" " " contents)))))
248
249
250 ;;;; Line Break
251
252 (defun org-md-line-break (line-break contents info)
253 "Transcode LINE-BREAK object into Markdown format.
254 CONTENTS is nil. INFO is a plist used as a communication
255 channel."
256 " \n")
257
258
259 ;;;; Link
260
261 (defun org-md-link (link contents info)
262 "Transcode LINE-BREAK object into Markdown format.
263 CONTENTS is the link's description. INFO is a plist used as
264 a communication channel."
265 (let ((--link-org-files-as-html-maybe
266 (function
267 (lambda (raw-path info)
268 ;; Treat links to `file.org' as links to `file.html', if
269 ;; needed. See `org-html-link-org-files-as-html'.
270 (cond
271 ((and org-html-link-org-files-as-html
272 (string= ".org"
273 (downcase (file-name-extension raw-path "."))))
274 (concat (file-name-sans-extension raw-path) "."
275 (plist-get info :html-extension)))
276 (t raw-path)))))
277 (type (org-element-property :type link)))
278 (cond ((member type '("custom-id" "id"))
279 (let ((destination (org-export-resolve-id-link link info)))
280 (if (stringp destination) ; External file.
281 (let ((path (funcall --link-org-files-as-html-maybe
282 destination info)))
283 (if (not contents) (format "<%s>" path)
284 (format "[%s](%s)" contents path)))
285 (concat
286 (and contents (concat contents " "))
287 (format "(%s)"
288 (format (org-export-translate "See section %s" :html info)
289 (mapconcat 'number-to-string
290 (org-export-get-headline-number
291 destination info)
292 ".")))))))
293 ((org-export-inline-image-p link org-html-inline-image-rules)
294 (let ((path (let ((raw-path (org-element-property :path link)))
295 (if (not (file-name-absolute-p raw-path)) raw-path
296 (expand-file-name raw-path)))))
297 (format "![%s](%s)"
298 (let ((caption (org-export-get-caption
299 (org-export-get-parent-element link))))
300 (when caption (org-export-data caption info)))
301 path)))
302 ((string= type "coderef")
303 (let ((ref (org-element-property :path link)))
304 (format (org-export-get-coderef-format ref contents)
305 (org-export-resolve-coderef ref info))))
306 ((equal type "radio")
307 (let ((destination (org-export-resolve-radio-link link info)))
308 (org-export-data (org-element-contents destination) info)))
309 ((equal type "fuzzy")
310 (let ((destination (org-export-resolve-fuzzy-link link info)))
311 (if (org-string-nw-p contents) contents
312 (when destination
313 (let ((number (org-export-get-ordinal destination info)))
314 (when number
315 (if (atom number) (number-to-string number)
316 (mapconcat 'number-to-string number "."))))))))
317 (t (let* ((raw-path (org-element-property :path link))
318 (path (cond
319 ((member type '("http" "https" "ftp"))
320 (concat type ":" raw-path))
321 ((equal type "file")
322 ;; Treat links to ".org" files as ".html",
323 ;; if needed.
324 (setq raw-path
325 (funcall --link-org-files-as-html-maybe
326 raw-path info))
327 ;; If file path is absolute, prepend it
328 ;; with protocol component - "file://".
329 (if (not (file-name-absolute-p raw-path)) raw-path
330 (concat "file://" (expand-file-name raw-path))))
331 (t raw-path))))
332 (if (not contents) (format "<%s>" path)
333 (format "[%s](%s)" contents path)))))))
334
335
336 ;;;; Paragraph
337
338 (defun org-md-paragraph (paragraph contents info)
339 "Transcode PARAGRAPH element into Markdown format.
340 CONTENTS is the paragraph contents. INFO is a plist used as
341 a communication channel."
342 (let ((first-object (car (org-element-contents paragraph))))
343 ;; If paragraph starts with a #, protect it.
344 (if (and (stringp first-object) (string-match "\\`#" first-object))
345 (replace-regexp-in-string "\\`#" "\\#" contents nil t)
346 contents)))
347
348
349 ;;;; Plain List
350
351 (defun org-md-plain-list (plain-list contents info)
352 "Transcode PLAIN-LIST element into Markdown format.
353 CONTENTS is the plain-list contents. INFO is a plist used as
354 a communication channel."
355 contents)
356
357
358 ;;;; Plain Text
359
360 (defun org-md-plain-text (text info)
361 "Transcode a TEXT string into Markdown format.
362 TEXT is the string to transcode. INFO is a plist holding
363 contextual information."
364 (when (plist-get info :with-smart-quotes)
365 (setq text (org-export-activate-smart-quotes text :html info)))
366 ;; Protect ambiguous #. This will protect # at the beginning of
367 ;; a line, but not at the beginning of a paragraph. See
368 ;; `org-md-paragraph'.
369 (setq text (replace-regexp-in-string "\n#" "\n\\\\#" text))
370 ;; Protect ambiguous !
371 (setq text (replace-regexp-in-string "\\(!\\)\\[" "\\\\!" text nil nil 1))
372 ;; Protect `, *, _ and \
373 (setq text (replace-regexp-in-string "[`*_\\]" "\\\\\\&" text))
374 ;; Handle special strings, if required.
375 (when (plist-get info :with-special-strings)
376 (setq text (org-html-convert-special-strings text)))
377 ;; Handle break preservation, if required.
378 (when (plist-get info :preserve-breaks)
379 (setq text (replace-regexp-in-string "[ \t]*\n" " \n" text)))
380 ;; Return value.
381 text)
382
383
384 ;;;; Quote Block
385
386 (defun org-md-quote-block (quote-block contents info)
387 "Transcode QUOTE-BLOCK element into Markdown format.
388 CONTENTS is the quote-block contents. INFO is a plist used as
389 a communication channel."
390 (replace-regexp-in-string
391 "^" "> "
392 (replace-regexp-in-string "\n\\'" "" contents)))
393
394
395 ;;;; Section
396
397 (defun org-md-section (section contents info)
398 "Transcode SECTION element into Markdown format.
399 CONTENTS is the section contents. INFO is a plist used as
400 a communication channel."
401 contents)
402
403
404 ;;;; Template
405
406 (defun org-md-template (contents info)
407 "Return complete document string after Markdown conversion.
408 CONTENTS is the transcoded contents string. INFO is a plist used
409 as a communication channel."
410 contents)
411
412
413 \f
414 ;;; Interactive function
415
416 ;;;###autoload
417 (defun org-md-export-as-markdown (&optional async subtreep visible-only)
418 "Export current buffer to a Markdown buffer.
419
420 If narrowing is active in the current buffer, only export its
421 narrowed part.
422
423 If a region is active, export that region.
424
425 A non-nil optional argument ASYNC means the process should happen
426 asynchronously. The resulting buffer should be accessible
427 through the `org-export-stack' interface.
428
429 When optional argument SUBTREEP is non-nil, export the sub-tree
430 at point, extracting information from the headline properties
431 first.
432
433 When optional argument VISIBLE-ONLY is non-nil, don't export
434 contents of hidden elements.
435
436 Export is done in a buffer named \"*Org MD Export*\", which will
437 be displayed when `org-export-show-temporary-export-buffer' is
438 non-nil."
439 (interactive)
440 (org-export-to-buffer 'md "*Org MD Export*"
441 async subtreep visible-only nil nil (lambda () (text-mode))))
442
443 ;;;###autoload
444 (defun org-md-convert-region-to-md ()
445 "Assume the current region has org-mode syntax, and convert it to Markdown.
446 This can be used in any buffer. For example, you can write an
447 itemized list in org-mode syntax in a Markdown buffer and use
448 this command to convert it."
449 (interactive)
450 (org-export-replace-region-by 'md))
451
452
453 ;;;###autoload
454 (defun org-md-export-to-markdown (&optional async subtreep visible-only)
455 "Export current buffer to a Markdown file.
456
457 If narrowing is active in the current buffer, only export its
458 narrowed part.
459
460 If a region is active, export that region.
461
462 A non-nil optional argument ASYNC means the process should happen
463 asynchronously. The resulting file should be accessible through
464 the `org-export-stack' interface.
465
466 When optional argument SUBTREEP is non-nil, export the sub-tree
467 at point, extracting information from the headline properties
468 first.
469
470 When optional argument VISIBLE-ONLY is non-nil, don't export
471 contents of hidden elements.
472
473 Return output file's name."
474 (interactive)
475 (let ((outfile (org-export-output-file-name ".md" subtreep)))
476 (org-export-to-file 'md outfile async subtreep visible-only)))
477
478
479 (provide 'ox-md)
480
481 ;; Local variables:
482 ;; generated-autoload-file: "org-loaddefs.el"
483 ;; End:
484
485 ;;; ox-md.el ends here