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.
This commit is contained in:
Jake Romer 2016-08-22 10:48:57 +02:00 committed by Nicolas Goaziou
parent cd18ac22ff
commit d4a073f5be
3 changed files with 89 additions and 16 deletions

View File

@ -14442,7 +14442,9 @@ however, override everything.
@subsubheading Markdown specific properties @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} @item @code{:md-headline-style} @tab @code{org-md-headline-style}
@end multitable @end multitable

View File

@ -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 ~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 default, the CSS styling of class ~org-svg~ specifies an image width
of 90\thinsp{}% of the container the image. 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 *** Babel
**** Blocks with coderefs labels can now be evaluated **** Blocks with coderefs labels can now be evaluated
The labels are removed prior to evaluating the block. The labels are removed prior to evaluating the block.

View File

@ -51,6 +51,25 @@ This variable can be set to either `atx' or `setext'."
(const :tag "Use \"Setext\" style" 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 ;;; Define Back-End
@ -89,7 +108,10 @@ This variable can be set to either `atx' or `setext'."
(src-block . org-md-example-block) (src-block . org-md-example-block)
(template . org-md-template) (template . org-md-template)
(verbatim . org-md-verbatim)) (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 ;;; Filters
@ -215,21 +237,30 @@ a communication channel."
(car (last (org-export-get-headline-number (car (last (org-export-get-headline-number
headline info)))) headline info))))
".")))) "."))))
(concat bullet (make-string (- 4 (length bullet)) ?\s) heading tags (concat bullet (make-string (- 4 (length bullet)) ?\s) heading tags "\n\n"
"\n\n" (and contents (replace-regexp-in-string "^" " " contents)))))
(and contents (t (concat (org-md--headline-title style level title anchor tags) 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))))))
;; 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 ;;;; Horizontal Rule
(defun org-md-horizontal-rule (_horizontal-rule _contents _info) (defun org-md-horizontal-rule (_horizontal-rule _contents _info)
@ -467,13 +498,48 @@ a communication channel."
;;;; Template ;;;; 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) (defun org-md-inner-template (contents info)
"Return body of document after converting it to Markdown syntax. "Return body of document after converting it to Markdown syntax.
CONTENTS is the transcoded contents string. INFO is a plist CONTENTS is the transcoded contents string. INFO is a plist
holding export options." holding export options."
;; Make sure CONTENTS is separated from table of contents and ;; Make sure CONTENTS is separated from table of contents and
;; footnotes with at least a blank line. ;; 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) (defun org-md-template (contents _info)
"Return complete document string after Markdown conversion. "Return complete document string after Markdown conversion.