Big Shield
Big Shield

Reputation: 622

How to make a table of contents in markdown-mode?

I am using emacs in markdown-mode to preview a markdown document, but there is no a table of contents in the HTML page previewed after typing C-x C-x p.

cat ~/.emacs

(add-to-list 'load-path "~/.emacs.d")  

(autoload 'markdown-mode "markdown-mode"
   "Major mode for editing Markdown files" t)
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))

(autoload 'gfm-mode "markdown-mode"
   "Major mode for editing GitHub Flavored Markdown files" t)
(add-to-list 'auto-mode-alist '("README\\.md\\'" . gfm-mode))

(custom-set-variables
 '(markdown-command "/usr/bin/pandoc --toc -f markdown_github -t html"))

PS: I can use pandoc command pandoc --toc -f markdown_github to make a HTML page with a table of contents from a markdown document.

How to solve it? Thx in advanced!

Upvotes: 7

Views: 6633

Answers (3)

yPhil
yPhil

Reputation: 8357

From my own init file:

(defun px/markdown-toc ()
  "Extract level 2 and 3 headings from the current Markdown buffer.
   The generated and indented TOC will be inserted at point."
  (interactive)
  (let (toc-list markdown-toc)
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward "^\\(##+\\)\\s-+\\(.*\\)" nil t)
        (let* ((level (length (match-string 1)))
               (heading-text (match-string 2))
               (heading-id (downcase (replace-regexp-in-string "[[:space:]]+" "-" heading-text))))
          (push (cons level (cons heading-text heading-id)) toc-list))))
    (setq toc-list (reverse toc-list))
    (dolist (item toc-list)
      (let* ((level (car item))
             (heading-text (cadr item))
             (heading-id (cddr item))
             (indentation (make-string (* 2 (1- level)) ?\ ))
             (line (format "- [%s](#%s)\n" heading-text heading-id)))
        (setq markdown-toc (concat markdown-toc (concat indentation line)))))
    (insert markdown-toc)))

Upvotes: 0

Ehvince
Ehvince

Reputation: 18375

It's super easy with the package markdown-toc, in melpa. Just call it with M-x.

source: http://wikemacs.org/wiki/Markdown#Generate_a_table_of_content

If you have many identical titles, the anchors have to be distinguished, and you'll rely on npm's markdown-toc.

Upvotes: 7

JosefAssad
JosefAssad

Reputation: 4118

If you have the discipline to insert named anchors under your headings like this:

## My heading
<a name="My heading"></a>
foo bar

My other heading
================
<a name="My other heading"></a>
baz qux

Then the following function ought to be a reasonable starting point (doesn't distinguish between heading levels or anything, just a little PoC).

(defun my/make-markdown-toc ()
  "Makes a markdown ToC at the top of a md document."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (let ((list-of-headings))
      (while (search-forward-regexp markdown-regex-header nil 'noerror)
    (if (match-string 5)
        (push (match-string 5) list-of-headings))
    (if (match-string 1)
        (push (match-string 1) list-of-headings)))
      (message "I found %s matches" (length list-of-headings))
      (goto-char (point-min))
      (dolist (heading (reverse list-of-headings))
    (insert "1. [" heading "](#" heading ")\n")))))

Note that the heavy lifting is just done by borrowing markdown-mode's regexes for headings.

Upvotes: 2

Related Questions