Generate table of contents in Markdown files based on headings
Project description
mark-toc
A Python tool which creates a Table of Contents for a Markdown document using the headings in the document as in-document hypertext link references.
Contents
Installing
It is recommended to install mark-toc either:
- In its own virtual environment (for example, using uv), or
- As a pre-commit hook
Once you have uv installed, you can use it to install mark-toc
as follows:
uv tool install mark-toc
How to Use
For a summary of all the available options:
uv tool run mark-toc --help
Or, with the uvx
shortcut:
uvx mark-toc --help
Or, if you prefer to call the script directly:
/path/to/mark-toc --help
[!TIP]
There are a number of different ways to run tools that are delivered as Python modules. For the remainder of this document, we will use
uvx mark-toc
to mean whichever one you prefer for your Python installation and operating environment.
How Does It Work?
mark-toc uses jiggerypokery to interpret and create "pseudo-comments" in the document text which are not rendered in most flavors of Markdown, including GitHub-flavored Markdown.
[!IMPORTANT]
mark-toc only handles the "atx"-style headings beginning with
#
, not the "setext"-style using "underlines" with=
or-
.
To insert a table of contents in your document, add the following text, at the beginning of an otherwise blank line and surrounded by blank lines, in the spot where you want the table of contents to appear:
[toc]: #
This is the "table of contents token". For example:
# README
This is the README.
[toc]: #
## More Info
...
Alternatively, you can use a "begin table of contents token" with a matching "end table of contents token":
[begintoc]: #
...
[endtoc]: #
Anything between the "begin" and "end" tokens will be replaced with the generated table of contents.
How Does It Really Work?
The "table of contents token" and begin/end tokens use the link reference definitions feature of Markdown to insert a link definition that is not intended to be referred to anywhere in the document.
As the CommonMark Spec notes:
A link reference definition does not correspond to a structural element of a document. Instead, it defines a label which can be used in reference links and reference-style images elsewhere in the document.
A link consisting of only #
is a valid HTML hyperlink target; it refers to
an empty fragment in the current document.
Example
This README contains begin/end tokens and serves as an example. You may need to view the "raw" source to see them.
Generating the Table of Contents
Once the token is in your Markdown file, run this script to generate a new document which includes a table of contents in place of the token. For example:
uvx mark-toc INPUTFILE.md
The result is printed to the standard output.
You can rerun this tool using a resulting document as the input, and the existing table of contents will be replaced by a new one in the output.
Heading Levels
By default, mark-toc includes all headings (except for the one starting the table of contents itself) in the resulting table of contents, and it prints the Contents heading as a top-level heading:
# Contents
However, it is not uncommon for Markdown documents on GitHub (like this README, for example) to use a "top-level" heading as the title of the document, and only second-level headings or greater throughout the rest of the document.
You can control what level the Contents heading appears at using the
--heading-level
option:
uvx mark-toc --heading-level 2 INPUTFILE.md
This results in:
## Contents
You can also control the "lowest" level of headings included in the table of
contents using --skip-level
. For example, to skip top-level headings, usE;
uvx mark-toc --skip-level 1 INPUTFILE.md
This will omit all headings that start with a sinle #
character from the
table of contents.
Combined, this looks lik:
uvx mark-toc --heading-level 2 --skip-level 1
or:
uvx mark-toc -H 2 -S 1
More Options
mark-toc has more options. There's built-in help:
uvx mark-toc --help
Pre-Commit Hook
mark-toc has built-in support for use with pre-commit as a
pre-commit hook. Simply add the following repo
and hook
to the repos
stanza in your .pre-commit-config.yaml
:
- repo: https://github.com/jmknoble/mark-toc
rev: v0.4.0
hooks:
- id: mark-toc
This uses the --pre-commit
option to modify Markdown files in place and emit a
message when a file is changed.
You can add arguments to the hook using the args
keyword; for example:
- repo: https://github.com/jmknoble/mark-toc
rev: v0.4.0
hooks:
- id: mark-toc
args: ['--heading-level', '2', '--skip-level', '1']
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.