Browse Source

ox-md.el: Export footnotes section as Markdown

* lisp/ox-md.el (org-md--headline-title): New function.
(org-md-headline): Use `org-md-headline-title' to generate section
headers.
(org-md--footnote-formatted): New function.
(org-md--footnote-section): New function.
(org-md-inner-template): Update to use `org-md-footnote-section'.
(org-md-footnotes-section): New customizable variable.
(org-md-footnote-format): New customizable variable.

Update ox-md.el to export the Footnotes section as Markdown, using HTML
only where necessary - namely, in footnote and footnote reference links.
Jake Romer 8 years ago
parent
commit
d4a073f5be
3 changed files with 90 additions and 17 deletions
  1. 3 1
      doc/org.texi
  2. 5 0
      etc/ORG-NEWS
  3. 82 16
      lisp/ox-md.el

+ 3 - 1
doc/org.texi

@@ -14442,7 +14442,9 @@ however, override everything.
 
 @subsubheading Markdown specific properties
 
-@multitable {@code{:md-headline-style}} {@code{org-md-headline-style}}
+@multitable {@code{:md-footnotes-section}} {@code{org-md-footnotes-section}}
+@item @code{:md-footnote-format} @tab @code{org-md-footnote-format}
+@item @code{:md-footnotes-section} @tab @code{org-md-footnotes-section}
 @item @code{:md-headline-style} @tab @code{org-md-headline-style}
 @end multitable
 

+ 5 - 0
etc/ORG-NEWS

@@ -219,6 +219,11 @@ SVG images exported in HTML are now by default assigned a CSS class
 ~org-svg~ if no CSS class is specified with the ~:class~ attribute. By
 default, the CSS styling of class ~org-svg~ specifies an image width
 of 90\thinsp{}% of the container the image.
+**** Markdown footnote export customization
+Variables ~org-md-footnotes-section~ and ~org-md-footnote-format~
+introduced for =ox-md.el=.  Both new variables define template strings
+which can be used to customize the format of the exported footnotes
+section and individual footnotes, respectively.
 *** Babel
 **** Blocks with coderefs labels can now be evaluated
 The labels are removed prior to evaluating the block.

+ 82 - 16
lisp/ox-md.el

@@ -51,6 +51,25 @@ This variable can be set to either `atx' or `setext'."
 	  (const :tag "Use \"Setext\" style" setext)))
 
 
+;;;; Footnotes
+
+(defcustom org-md-footnotes-section "%s%s"
+  "Format string for the footnotes section.
+The first %s placeholder will be replaced with the localized Footnotes section
+heading, the second with the contents of the Footnotes section."
+ :group 'org-export-md
+ :type 'string
+ :version "25.1"
+ :package-version '(Org . "9.0"))
+
+(defcustom org-md-footnote-format "<sup>%s</sup>"
+  "Format string for the footnote reference.
+The %s will be replaced by the footnote reference itself."
+  :group 'org-export-md
+  :type 'string
+  :version "25.1"
+  :package-version '(Org . "9.0"))
+
 
 ;;; Define Back-End
 
@@ -89,7 +108,10 @@ This variable can be set to either `atx' or `setext'."
 		     (src-block . org-md-example-block)
 		     (template . org-md-template)
 		     (verbatim . org-md-verbatim))
-  :options-alist '((:md-headline-style nil nil org-md-headline-style)))
+  :options-alist
+  '((:md-footnote-format nil nil org-md-footnote-format)
+    (:md-footnotes-section nil nil org-md-footnotes-section)
+    (:md-headline-style nil nil org-md-headline-style)))
 
 
 ;;; Filters
@@ -215,20 +237,29 @@ a communication channel."
 			  (car (last (org-export-get-headline-number
 				      headline info))))
 			 "."))))
-	  (concat bullet (make-string (- 4 (length bullet)) ?\s) heading tags
-		  "\n\n"
-		  (and contents
-		       (replace-regexp-in-string "^" "    " contents)))))
-       ;; Use "Setext" style.
-       ((eq style 'setext)
-	(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 anchor "\n\n"
-		  contents))))))
-
+	  (concat bullet (make-string (- 4 (length bullet)) ?\s) heading tags "\n\n"
+		  (and contents (replace-regexp-in-string "^" "    " contents)))))
+       (t (concat (org-md--headline-title style level title anchor tags) contents))))))
+
+
+;; Headline Title
+
+(defun org-md--headline-title (style level title &optional anchor tags)
+  "Generate a headline title in the preferred Markdown headline style.
+STYLE is the preferred style (`atx' or `setext').  LEVEL is the
+header level.  TITLE is the headline title.  ANCHOR is the HTML
+anchor tag for the section as a string.  TAGS are the tags set on
+the section."
+  (let ((anchor-lines (and anchor (concat anchor "\n\n"))))
+    ;; Use "Setext" style
+    (if (and (eq style 'setext) (< level 3))
+        (let* ((underline-char (if (= level 1) ?= ?-))
+               (underline (concat (make-string (length title) underline-char)
+				  "\n")))
+          (concat "\n" anchor-lines title tags "\n" underline "\n"))
+        ;; Use "Atx" style
+        (let ((level-mark (make-string level ?#)))
+          (concat "\n" anchor-lines level-mark " " title tags "\n\n")))))
 
 ;;;; Horizontal Rule
 
@@ -467,13 +498,48 @@ a communication channel."
 
 ;;;; Template
 
+(defun org-md--footnote-formatted (footnote info)
+  "Formats a single footnote entry FOOTNOTE.
+FOOTNOTE is a cons cell of the form (number . definition).
+INFO is a plist with contextual information."
+  (let* ((fn-num (car footnote))
+         (fn-text (cdr footnote))
+         (fn-format (plist-get info :md-footnote-format))
+         (fn-anchor (format "fn.%d" fn-num))
+         (fn-href (format " href=\"#fnr.%d\"" fn-num))
+         (fn-link-to-ref (org-html--anchor fn-anchor fn-num fn-href info)))
+    (concat (format fn-format fn-link-to-ref) " " fn-text "\n")))
+
+(defun org-md--footnote-section (info)
+  "Format the footnote section.
+INFO is a plist used as a communication channel."
+  (let* ((fn-alist (org-export-collect-footnote-definitions info))
+         (fn-alist (cl-loop for (n type raw) in fn-alist collect
+                            (cons n (org-trim (org-export-data raw info)))))
+         (headline-style (plist-get info :md-headline-style))
+         (section-title (org-html--translate "Footnotes" info)))
+    (when fn-alist
+      (format (plist-get info :md-footnotes-section)
+              (org-md--headline-title headline-style 1 section-title)
+              (mapconcat (lambda (fn) (org-md--footnote-formatted fn info))
+                         fn-alist
+                         "\n")))))
+
 (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)))
+  (concat
+   ;; Table of contents.
+   (let ((depth (plist-get info :with-toc)))
+     (when depth (org-html-toc depth info)))
+   ;; Document contents.
+   contents
+   "\n"
+   ;; Footnotes section.
+   (org-md-footnote--section info)))
 
 (defun org-md-template (contents _info)
   "Return complete document string after Markdown conversion.