]> code.delx.au - gnu-emacs/blobdiff - lisp/org/ox-md.el
Update docs for `customize-mode'
[gnu-emacs] / lisp / org / ox-md.el
index 78420170b8a7287f7f1eb3cf87054a4283874a7b..102c4a5d1159a7747ff31e3c4a98bae8fc21001b 100644 (file)
@@ -1,6 +1,6 @@
 ;;; ox-md.el --- Markdown Back-End for Org Export Engine
 
-;; Copyright (C) 2012-2013 Free Software Foundation, Inc.
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
 
 ;; Author: Nicolas Goaziou <n.goaziou@gmail.com>
 ;; Keywords: org, wp, markdown
@@ -77,6 +77,7 @@ This variable can be set to either `atx' or `setext'."
                     (headline . org-md-headline)
                     (horizontal-rule . org-md-horizontal-rule)
                     (inline-src-block . org-md-verbatim)
+                    (inner-template . org-md-inner-template)
                     (italic . org-md-italic)
                     (item . org-md-item)
                     (line-break . org-md-line-break)
@@ -96,19 +97,33 @@ This variable can be set to either `atx' or `setext'."
 ;;; Filters
 
 (defun org-md-separate-elements (tree backend info)
-  "Make sure elements are separated by at least one blank line.
+  "Fix blank lines between elements.
 
 TREE is the parse tree being exported.  BACKEND is the export
 back-end used.  INFO is a plist used as a communication channel.
 
+Enforce a blank line between elements.  There are three
+exceptions to this rule:
+
+  1. Preserve blank lines between sibling items in a plain list,
+
+  2. Outside of plain lists, preserve blank lines between
+     a paragraph and a plain list,
+
+  3. In an item, remove any blank line before the very first
+     paragraph and the next sub-list.
+
 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)))))))
+  (org-element-map tree (remq 'item org-element-all-elements)
+    (lambda (e)
+      (cond
+       ((not (and (eq (org-element-type e) 'paragraph)
+                 (eq (org-element-type (org-export-get-next-element e info))
+                     'plain-list)))
+       (org-element-put-property e :post-blank 1))
+       ((not (eq (org-element-type (org-element-property :parent e)) 'item)))
+       (t (org-element-put-property
+          e :post-blank (if (org-export-get-previous-element e info) 1 0))))))
   ;; Return updated tree.
   tree)
 
@@ -149,7 +164,7 @@ channel."
   (replace-regexp-in-string
    "^" "    "
    (org-remove-indentation
-    (org-element-property :value example-block))))
+    (org-export-format-code-default example-block info))))
 
 
 ;;;; Headline
@@ -174,6 +189,14 @@ a communication channel."
            (and (plist-get info :with-priority)
                 (let ((char (org-element-property :priority headline)))
                   (and char (format "[#%c] " char)))))
+          (anchor
+           (when (plist-get info :with-toc)
+             (org-html--anchor
+              (or (org-element-property :CUSTOM_ID headline)
+                  (concat "sec-"
+                          (mapconcat 'number-to-string
+                                     (org-export-get-headline-number
+                                      headline info) "-"))))))
           ;; Headline text without tags.
           (heading (concat todo priority title)))
       (cond
@@ -194,12 +217,12 @@ a communication channel."
                       (replace-regexp-in-string "^" "    " contents)))))
        ;; Use "Setext" style.
        ((eq org-md-headline-style 'setext)
-       (concat heading tags "\n"
+       (concat heading tags anchor "\n"
                (make-string (length heading) (if (= level 1) ?= ?-))
                "\n\n"
                contents))
        ;; Use "atx" style.
-       (t (concat (make-string level ?#) " " heading tags "\n\n" contents))))))
+       (t (concat (make-string level ?#) " " heading tags anchor "\n\n" contents))))))
 
 
 ;;;; Horizontal Rule
@@ -244,7 +267,8 @@ a communication channel."
              (off "[ ] "))
            (let ((tag (org-element-property :tag item)))
              (and tag (format "**%s:** "(org-export-data tag info))))
-           (org-trim (replace-regexp-in-string "^" "    " contents)))))
+           (and contents
+                (org-trim (replace-regexp-in-string "^" "    " contents))))))
 
 
 ;;;; Line Break
@@ -262,75 +286,73 @@ channel."
   "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
+  (let ((link-org-files-as-md
         (function
-         (lambda (raw-path info)
-           ;; Treat links to `file.org' as links to `file.html', if
-            ;; needed.  See `org-html-link-org-files-as-html'.
-           (cond
-            ((and org-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)))))
+         (lambda (raw-path)
+           ;; Treat links to `file.org' as links to `file.md'.
+           (if (string= ".org" (downcase (file-name-extension raw-path ".")))
+               (concat (file-name-sans-extension raw-path) ".md")
+             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-html-inline-image-rules)
-          (let ((path (let ((raw-path (org-element-property :path link)))
-                        (if (not (file-name-absolute-p raw-path)) raw-path
-                          (expand-file-name raw-path)))))
-            (format "![%s](%s)"
-                    (let ((caption (org-export-get-caption
-                                    (org-export-get-parent-element link))))
-                      (when caption (org-export-data 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)))
-            (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")
-                           ;; 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)))))))
+    (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-md destination)))
+             (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-html-inline-image-rules)
+      (let ((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-export-data
+                     (org-export-get-caption
+                      (org-export-get-parent-element link)) info)))
+       (format "![img](%s)"
+               (if (not (org-string-nw-p caption)) path
+                 (format "%s \"%s\"" path caption)))))
+     ((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") contents)
+     ((equal type "fuzzy")
+      (let ((destination (org-export-resolve-fuzzy-link link info)))
+       (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 "."))))))))
+     ;; Link type is handled by a special function.
+     ((let ((protocol (nth 2 (assoc type org-link-protocols))))
+       (and (functionp protocol)
+            (funcall protocol
+                     (org-link-unescape (org-element-property :path link))
+                     contents
+                     'md))))
+     (t (let* ((raw-path (org-element-property :path link))
+              (path
+               (cond
+                ((member type '("http" "https" "ftp"))
+                 (concat type ":" raw-path))
+                ((string= type "file")
+                 (let ((path (funcall link-org-files-as-md raw-path)))
+                   (if (not (file-name-absolute-p path)) path
+                     ;; If file path is absolute, prepend it
+                     ;; with "file:" component.
+                     (concat "file:" path))))
+                (t raw-path))))
+         (if (not contents) (format "<%s>" path)
+           (format "[%s](%s)" contents path)))))))
 
 
 ;;;; Paragraph
@@ -403,6 +425,14 @@ a communication channel."
 
 ;;;; Template
 
+(defun org-md-inner-template (contents info)
+  "Return body of document after converting it to Markdown syntax.
+CONTENTS is the transcoded contents string.  INFO is a plist
+holding export options."
+  ;; Make sure CONTENTS is separated from table of contents and
+  ;; footnotes with at least a blank line.
+  (org-trim (org-html-inner-template (concat "\n" contents "\n") info)))
+
 (defun org-md-template (contents info)
   "Return complete document string after Markdown conversion.
 CONTENTS is the transcoded contents string.  INFO is a plist used