I have added options to use Markdown Extra-style footnotes and example
blocks to ox-md.

Markdown Extra is used by many different Markdown engines. You can read
more about it here: https://michelf.ca/projects/php-markdown/extra/

-- 
Erik L. Arneson
Computer Research Consultant
earne...@arnesonium.com
+1 541.291.9776

>From b1f0a0376cf967336ffe653faa9b2c8f138a2575 Mon Sep 17 00:00:00 2001
From: "Erik L. Arneson" <earne...@arnesonium.com>
Date: Sun, 20 Dec 2015 13:25:08 -0800
Subject: [PATCH] ox-md: Markdown Extra for footnotes and example blocks

Add Markdown Extra support for footnotes and example blocks.

* lisp/ox-md.el:
(org-md-footnote-style):
(org-md--extra-footnote-section):
(org-md-footnote-section):
(org-md--extra-footnote-reference):
(org-md-footnote-reference): Markdown Extra footnote style.
(org-md-headline): Format Footnotes headline
(org-md-example-block): Markdown Extra example block
(org-md-inner-template): Handle footnotes in ox-md
---
 lisp/ox-md.el | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 75 insertions(+), 8 deletions(-)

diff --git a/lisp/ox-md.el b/lisp/ox-md.el
index 713061f..6d8d614 100644
--- a/lisp/ox-md.el
+++ b/lisp/ox-md.el
@@ -50,6 +50,20 @@ This variable can be set to either `atx' or `setext'."
 	  (const :tag "Use \"atx\" style" atx)
 	  (const :tag "Use \"Setext\" style" setext)))
 
+(defcustom org-md-footnote-style 'html
+  "Style used to format footnotes.
+This variable can be set to either `html' or `extra'. The
+`extra' version uses carat-style footnotes that are supported
+by Markdown Extra."
+  :group 'org-export-md
+  :type '(choice
+	  (const :tag "Use raw HTML footnotes" html)
+	  (const :tag "Use carat-style footnotes" extra)))
+
+(defcustom org-md-example-block-extra nil
+  "If non-nil, use Markdown Extra formatting for example blocks."
+  :group 'org-export-md
+  :type 'boolean)
 
 
 ;;; Define Back-End
@@ -71,6 +85,8 @@ This variable can be set to either `atx' or `setext'."
 		     (example-block . org-md-example-block)
 		     (export-block . org-md-export-block)
 		     (fixed-width . org-md-example-block)
+		     (footnote-definition . org-md-footnote-definition)
+		     (footnote-reference . org-md-footnote-reference)
 		     (headline . org-md-headline)
 		     (horizontal-rule . org-md-horizontal-rule)
 		     (inline-src-block . org-md-verbatim)
@@ -160,10 +176,17 @@ channel."
   "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-export-format-code-default example-block info))))
+  (concat
+   (if org-md-example-block-extra
+       "```\n"
+     "")
+   (replace-regexp-in-string
+    "^" "    "
+    (org-remove-indentation
+     (org-export-format-code-default example-block info)))
+   (if org-md-example-block-extra
+       "\n```\n"
+     "")))
 
 (defun org-md-export-block (export-block contents info)
   "Transcode a EXPORT-BLOCK element from Org to Markdown.
@@ -174,13 +197,51 @@ CONTENTS is nil.  INFO is a plist holding contextual information."
     (org-export-with-backend 'html export-block contents info)))
 
 
+;;;; Footnote Section
+
+(defun org-md--extra-footnote-section (info)
+  (let* ((fn-alist (org-export-collect-footnote-definitions 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))
+			  (org-trim (org-export-data raw info)))))))
+    (mapconcat
+     (lambda (fn)
+       (let ((n (car fn))
+	     (def (cdr fn)))
+	 (format "[^%d]: %s"
+		 n def)))
+     fn-alist "\n\n")))
+
+(defun org-md-footnote-section (info)
+  "Format the footnote section.
+INFO is a plist used as a communication channel."
+  (cond ((eq org-md-footnote-style 'html)
+	 (org-html-footnote-section info))
+	((eq org-md-footnote-style 'extra)
+	 (org-md--extra-footnote-section info))))
+
+;;;; Footnote Reference
+(defun org-md--extra-footnote-reference (footnote-reference _contents info)
+  (format "[^%d]" (org-export-get-footnote-number footnote-reference info)))
+
+(defun org-md-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."
+  (cond ((eq org-md-footnote-style 'html)
+	 (org-html-footnote-reference footnote-reference _contents info))
+	((eq org-md-footnote-style 'extra)
+	 (org-md--extra-footnote-reference footnote-reference _contents info))))
+
 ;;;; 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)
+  (unless (and (eq org-md-footnote-style 'html)
+	       (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)
@@ -472,9 +533,15 @@ a communication channel."
   "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)))
+  (org-trim
+   (concat
+    ;; Table of contents.
+    (let ((depth (plist-get info :with-toc)))
+      (when depth (org-html-toc depth info)))
+    ;; Document contents.
+    "\n" contents "\n"
+    ;; Footnotes section.
+    (org-md-footnote-section info))))
 
 (defun org-md-template (contents _info)
   "Return complete document string after Markdown conversion.
-- 
2.5.0

Reply via email to