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