|
@@ -248,15 +248,42 @@ a communication channel."
|
|
|
"Non-nil when HEADLINE is being referred to.
|
|
|
INFO is a plist used as a communication channel. Links and table
|
|
|
of contents can refer to headlines."
|
|
|
- (or (plist-get info :with-toc)
|
|
|
- (org-element-map (plist-get info :parse-tree) 'link
|
|
|
- (lambda (link)
|
|
|
- (eq headline
|
|
|
- (pcase (org-element-property :type link)
|
|
|
- ((or "custom-id" "id") (org-export-resolve-id-link link info))
|
|
|
- ("fuzzy" (org-export-resolve-fuzzy-link link info))
|
|
|
- (_ nil))))
|
|
|
- info t)))
|
|
|
+ (unless (org-element-property :footnote-section-p headline)
|
|
|
+ (or
|
|
|
+ ;; Global table of contents includes HEADLINE.
|
|
|
+ (and (plist-get info :with-toc)
|
|
|
+ (memq headline
|
|
|
+ (org-export-collect-headlines info (plist-get info :with-toc))))
|
|
|
+ ;; A local table of contents includes HEADLINE.
|
|
|
+ (cl-some
|
|
|
+ (lambda (h)
|
|
|
+ (let ((section (car (org-element-contents h))))
|
|
|
+ (and
|
|
|
+ (eq 'section (org-element-type section))
|
|
|
+ (org-element-map section 'keyword
|
|
|
+ (lambda (keyword)
|
|
|
+ (when (equal "TOC" (org-element-property :key keyword))
|
|
|
+ (let ((case-fold-search t)
|
|
|
+ (value (org-element-property :value keyword)))
|
|
|
+ (and (string-match-p "\\<headlines\\>" value)
|
|
|
+ (let ((n (and
|
|
|
+ (string-match "\\<[0-9]+\\>" value)
|
|
|
+ (string-to-number (match-string 0 value))))
|
|
|
+ (local? (string-match-p "\\<local\\>" value)))
|
|
|
+ (memq headline
|
|
|
+ (org-export-collect-headlines
|
|
|
+ info n (and local? keyword))))))))
|
|
|
+ info t))))
|
|
|
+ (org-element-lineage headline))
|
|
|
+ ;; A link refers internally to HEADLINE.
|
|
|
+ (org-element-map (plist-get info :parse-tree) 'link
|
|
|
+ (lambda (link)
|
|
|
+ (eq headline
|
|
|
+ (pcase (org-element-property :type link)
|
|
|
+ ((or "custom-id" "id") (org-export-resolve-id-link link info))
|
|
|
+ ("fuzzy" (org-export-resolve-fuzzy-link link info))
|
|
|
+ (_ nil))))
|
|
|
+ info t))))
|
|
|
|
|
|
(defun org-md--headline-title (style level title &optional anchor tags)
|
|
|
"Generate a headline title in the preferred Markdown headline style.
|
|
@@ -328,9 +355,19 @@ a communication channel."
|
|
|
"Transcode a KEYWORD element into Markdown format.
|
|
|
CONTENTS is nil. INFO is a plist used as a communication
|
|
|
channel."
|
|
|
- (if (member (org-element-property :key keyword) '("MARKDOWN" "MD"))
|
|
|
- (org-element-property :value keyword)
|
|
|
- (org-export-with-backend 'html keyword contents info)))
|
|
|
+ (pcase (org-element-property :key keyword)
|
|
|
+ ((or "MARKDOWN" "MD") (org-element-property :value keyword))
|
|
|
+ ("TOC"
|
|
|
+ (let ((case-fold-search t)
|
|
|
+ (value (org-element-property :value keyword)))
|
|
|
+ (cond
|
|
|
+ ((string-match-p "\\<headlines\\>" value)
|
|
|
+ (let ((depth (and (string-match "\\<[0-9]+\\>" value)
|
|
|
+ (string-to-number (match-string 0 value))))
|
|
|
+ (local? (string-match-p "\\<local\\>" value)))
|
|
|
+ (org-remove-indentation
|
|
|
+ (org-md--build-toc info depth keyword local?)))))))
|
|
|
+ (_ (org-export-with-backend 'html keyword contents info))))
|
|
|
|
|
|
|
|
|
;;;; Line Break
|
|
@@ -512,6 +549,61 @@ a communication channel."
|
|
|
|
|
|
;;;; Template
|
|
|
|
|
|
+(defun org-md--build-toc (info &optional n keyword local)
|
|
|
+ "Return a table of contents.
|
|
|
+
|
|
|
+INFO is a plist used as a communication channel.
|
|
|
+
|
|
|
+Optional argument N, when non-nil, is an integer specifying the
|
|
|
+depth of the table.
|
|
|
+
|
|
|
+Optional argument KEYWORD specifies the TOC keyword, if any, from
|
|
|
+which the table of contents generation has been initiated.
|
|
|
+
|
|
|
+When optional argument LOCAL is non-nil, build a table of
|
|
|
+contents according to the current headline."
|
|
|
+ (concat
|
|
|
+ (unless local
|
|
|
+ (let ((style (plist-get info :md-headline-style))
|
|
|
+ (title (org-html--translate "Table of Contents" info)))
|
|
|
+ (org-md--headline-title style 1 title nil)))
|
|
|
+ (mapconcat
|
|
|
+ (lambda (headline)
|
|
|
+ (let* ((indentation
|
|
|
+ (make-string
|
|
|
+ (* 4 (1- (org-export-get-relative-level headline info)))
|
|
|
+ ?\s))
|
|
|
+ (number (format "%d."
|
|
|
+ (org-last
|
|
|
+ (org-export-get-headline-number headline info))))
|
|
|
+ (bullet (concat number (make-string (- 4 (length number)) ?\s)))
|
|
|
+ (title
|
|
|
+ (format "[%s](#%s)"
|
|
|
+ (org-export-data-with-backend
|
|
|
+ (org-export-get-alt-title headline info)
|
|
|
+ ;; Create an anonymous back-end that will
|
|
|
+ ;; ignore any footnote-reference, link,
|
|
|
+ ;; radio-target and target in table of
|
|
|
+ ;; contents.
|
|
|
+ (org-export-create-backend
|
|
|
+ :parent 'md
|
|
|
+ :transcoders '((footnote-reference . ignore)
|
|
|
+ (link . (lambda (object c i) c))
|
|
|
+ (radio-target . (lambda (object c i) c))
|
|
|
+ (target . ignore)))
|
|
|
+ info)
|
|
|
+ (or (org-element-property :CUSTOM_ID headline)
|
|
|
+ (org-export-get-reference headline info))))
|
|
|
+ (tags (and (plist-get info :with-tags)
|
|
|
+ (not (eq 'not-in-toc (plist-get info :with-tags)))
|
|
|
+ (let ((tags (org-export-get-tags headline info)))
|
|
|
+ (and tags
|
|
|
+ (format ":%s:"
|
|
|
+ (mapconcat #'identity tags ":")))))))
|
|
|
+ (concat indentation bullet title tags)))
|
|
|
+ (org-export-collect-headlines info n (and local keyword)) "\n")
|
|
|
+ "\n"))
|
|
|
+
|
|
|
(defun org-md--footnote-formatted (footnote info)
|
|
|
"Formats a single footnote entry FOOTNOTE.
|
|
|
FOOTNOTE is a cons cell of the form (number . definition).
|
|
@@ -548,7 +640,8 @@ holding export options."
|
|
|
(concat
|
|
|
;; Table of contents.
|
|
|
(let ((depth (plist-get info :with-toc)))
|
|
|
- (when depth (org-html-toc depth info)))
|
|
|
+ (when depth
|
|
|
+ (concat (org-md--build-toc info (and (wholenump depth) depth)) "\n")))
|
|
|
;; Document contents.
|
|
|
contents
|
|
|
"\n"
|