Utility to number headings and generate Table of contents for Markdown files.

Table of Contents

  1. Overview
  2. Usage
  3. Installation
  4. Limtations

1. Overview

This utility adds heading numbers and a table of contents to a Markdown file.

It is used to make long Markdown files easier to navigate and read.

For example, it takes a Markdown file containing:

|  Document title
|  ==============
|
|  ## Alpha
|
|  ### Foo
|
|  ### Bar
|
|  ## Beta
|
|  ## Gamma

And generates:

|  Document title
|  ==============
|
|  ## Table of contents
|
|  1. Alpha
|      - 1.1 Foo
|      - 1.2 Bar
|  2. Beta
|  3. Gamma
|
|  ## 1. Alpha
|
|  ### 1.1 Foo
|
|  ### 1.2 Bar
|
|  ## 2. Beta
|
|  ## 3. Gamma

Note: this README has been processed by the utility, to automatically generate the above Table of Contents and the numbered headings. The Markdown in the embedded examples start with extra "|" at the beginning of the lines, to prevent the utility from recognising their contents as headings for it to process.

This is a simplified example: the actual output also contains hyperlinks from the entries in the table of contents to the sections they refer to.

The utility can also update the numbering and table of contents. It can be re-run on its own output: which is useful if headings have been added, changed or removed.

It can also be used to strip out the table of contents and heading numbers. That is, to revert it back to the original input Markdown.

2. Usage

2.1. Summary

Usage: markdown_toc [options] {markdown-files}
Options:
-t | --top-level N  lowest numbered heading level (default: 2)
-n | --num-level N  highest heading level to number (default: 5)
-i | --toc-level N  highest heading level to include in table of contents (default: 4)

-o | --output FILE  write result to named output file (default: stdout)
-r | --replace      replace input file with the result instead of to output

-s | --strip        remove ToC and numbering, instead of adding/updating them

-v | --verbose      output extra information when running
     --version      display version information and exit
-h | --help         display this help and exit

2.2. Producing output

By default, the results are written to stdout:

$ markdown_toc.dart example.md

But the utility is usually invoked to replace the input file with the results:

$ markdown_toc.dart --replace example.md

Alternatively, a different output file can be specified:

$ markdown_toc.dart --output example-with-toc.md example.md

2.3. Heading syntax

The utility only processes headers that use the leading "#" Markdown syntax. It ignores headers that use the underline Markdown syntax.

2.4. Table of contents

The table of contents is inserted immediately before the first recognised heading.

2.5. Heading levels

2.5.1. Default processes level 2 headings and higher

If it processes level 2 headers and higher (the default), this allows the document's title to be formatted as a level 1 heading using the underline syntax. It will ignore the title (i.e. not number it and not include it in the table of contents) and insert the table of contents immediately before the first non-ignored heading.

And the default maximum numbered level is 5. Headings at level 6 and greater (i.e. those starting with Markdown "######") will not be numbered.

The maximum level to include in the table of contents is 4. Headings at level 5 and greater (i.e. those starting with Markdown "#####") will not be included in the table of contents (even if they are numbered).

For example,

|  Title
|  =====
|
|  ## First
|
|  ### Subsection
|
|  ## Second
|

Will produce:

|  Title
|  =====
|
|  ## Table of Contents
|
|  ...
|
|  ## 1. First
|
|  ### 1.1. Subsection
|
|  ## 2. Second

2.5.2. Changing the level of processed headings

The heading levels which are processed is changed using the --top-level, --num-level and --toc-level options.

For example, some Markdown files use a metadata block for the document title and level 1 headings used as normal headings.

|  % The document's title
|  % Author
|  % Version 1.0.0
|
|  # First
|
|  ## Subsection
|
|  # Second

Use the --top-level option to include the level 1 headings:

$ markdown_toc --top-level 1  example.md

Produces:

|  % The document's title
|  % Author
|  % Version 1.0.0
|
|  # Table of contents
|
|  ...
|
|  # 1. First
|
|  ## 1.1 Subsection
|
|  # 2. Second

2.6. Removing the table of contents and numbering

Use the --strip option to remove the information added by the utility.

$ markdown_toc.dart --strip example-with-toc.md

3. Installation

markdow_toc is not meant to be used as a dependncy. Instead, it should be installed.

There are a number of ways it can be installed.

3.1. Dart

When used to manage Markdown files in a Dart project, this utility can be made a development dependency of the project.

3.1.1. Dependency of a Dart project

This utility is intended to be included in a Dart project development dependency, so it can be used to add numbered headings and table of contents to long Markdown documents in the project.

In pubspec.yaml add:

dev_dependencies:
  markdown_toc: ^1.1.0

Then run:

$ dart pub get

The utility should be run using the "dart run" command, to run the specific version of the utility that was installed by "dart pub get".

$ dart run markdown_toc --help

3.1.2. Global install

Alternatively, install it using "dart pub global activate" so it can be used on any Markdown files (not just those used to document Dart projects).

$ dart pub global activate markdown_toc

If the global directory is on the PATH, the utility can be run using:

$ markdown_toc --help

Or it can always be run with:

dart pub global run markdown_toc --help

3.1.3. Script runs anywhere Dart is available

Finally, the utility has been written to not use any pub packages. So it can be run anywhere; as long as the dart executable is available. There is no need for it to be inside a Dart project, nor to have an associated pubspec.yaml file.

Copy the markdown_toc.dart file to somewhere on the PATH:

$ cp markdown_toc.dart /usr/local/bin/markdown_toc

And then run it as a normal command:

$ markdown_toc --help

3.1.4. Compiled executable runs without needing Dart

Compile it to a self-contained executable. Which can be run anywhere, without needing the Dart executable.

dart compile exe bin/markdown_toc.dart

bin/markdown_toc --help

3.2. Binary

Binaries can be downloaded from the project's GitHub releases.

Copy the program to a location in your PATH.

4. Limtations

4.1. Fenced code blocks may be incorrectly treated as headings

The lines inside fenced code blocks (i.e. lines between lines starting with ```) are not treated as different. If they contain lines starting with "#" (with or without whitespace before it), they may be incorrectly processed as headings.

Since the --top-level is usually set to 2 or higher. This problem only occurs when lines inside the fenced code blocks start with two or more "#", which may not occur.

A workaround is to modify the lines inside the fenced code blocks. For example, by adding a prefix to them so they don't start with the "#".

Libraries