Skip to content

Instantly share code, notes, and snippets.

@jg-you
Last active July 7, 2020 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jg-you/aa6ce468601fc11c3d0b to your computer and use it in GitHub Desktop.
Save jg-you/aa6ce468601fc11c3d0b to your computer and use it in GitHub Desktop.
Generate TOC for a markdown file
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @author: Jean-Gabriel Young <jean.gabriel.young@gmail.com>
"""Generate TOC for a markdown file."""
import re
# Match between 1 and 4 #
section = re.compile('^\s*(#){1,4}\s?')
strip_url = re.compile('[\W_]+', re.UNICODE)
def gen_toc(markdown_file):
"""Generate TOC for a markdown file."""
toc_content = []
for l in markdown_file:
match = section.match(l)
if match is not None:
level = match.group().count('#') - 1
title = strip_url.sub(' ', section.sub('', l)).strip()
url = title.replace(' ', '-').lower()
toc_content.append((level, title, url))
toc = []
numerotation = [1, 1, 1, 1]
for item in toc_content:
toc.append(' ' * (item[0]) + str(numerotation[item[0]]) +
". " + "[" + item[1] + "](#" + item[2] + ")")
numerotation[item[0]] += 1
numerotation[item[0] + 1:] = [1] * (3 - item[0])
return toc
if __name__ == "__main__":
# Options parser.
import argparse as ap
import sys
prs = ap.ArgumentParser(description="Generate TOC for a markdown file.")
prs.add_argument('markdown_file', type=str,
help='Markdown file')
if len(sys.argv) == 1:
prs.print_help()
sys.exit(1)
args = prs.parse_args()
with open(args.markdown_file, 'r') as f:
toc = gen_toc(f)
for item in toc:
print(item)

Top level

Sub-section A

Sub-section B

Sub-sub-section B.1

Sub-section C

Sub-sub-section C.1

Sub-sub-section C.2

> python mdown_toc.py mdown_toc_example.md
1. [Top level](#top-level)
1. [Sub section A](#sub-section-a)
2. [Sub section B](#sub-section-b)
1. [Sub sub section B 1](#sub-sub-section-b-1)
3. [Sub section C](#sub-section-c)
1. [Sub sub section C 1](#sub-sub-section-c-1)
2. [Sub sub section C 2](#sub-sub-section-c-2)
@jg-you
Copy link
Author

jg-you commented Mar 19, 2016

Probably not robust, but it works for me.

@DutchPete
Copy link

Couple of questions:

  • does this work on any markdown file
  • is python 3 absolutely necessary? I have 2.7.16
  • how do you set off the script: just type ./mdown_toc.py?

@jg-you
Copy link
Author

jg-you commented Jul 3, 2020

does this work on any markdown file

sure, it just matches leading "#" chars to find the sectionning.

is python 3 absolutely necessary? I have 2.7.16

probably, try changing the print statements and so on.

how do you set off the script: just type ./mdown_toc.py?

you'd have to do python mdown_toc.py or you can chmod +x the script and execute (if you correct the leading #! to whatever python env you have)

@DutchPete
Copy link

It's easier to install Python 3, so I'll do that.

Please excuse my basic, noob question. but I assume in the terminal you have to change directory where the .md files are.

  1. If you then run the script, it means it will generate TOCs for all the files in there, right?
  2. You cannot run it on a single file, unless you make a separate folder with just that one test file in it, right?
  3. Where are the TOCs stored? In a newly created file?

@DutchPete
Copy link

I hope you'll answer.

I installed Python 3, then open a separate test folder, with 1 markdown file that contains # headers.
I placed a copy of your script in that folder, opened a terminal, cd to the test folder, ran the script with python mdown_toc.py, and got this as the output:

usage: mdown_toc.py [-h] markdown_file

Generate TOC for a markdown file.

positional arguments:
  markdown_file  Markdown file

optional arguments:
  -h, --help     show this help message and exit

There is no new file in the test folder, there is no TOC at the top of the test file.
Please advise on corrections.

@jg-you
Copy link
Author

jg-you commented Jul 6, 2020

If you then run the script, it means it will generate TOCs for all the files in there, right?

No, I setup the main to parse a single file python mdown_toc.py file.md.

You cannot run it on a single file, unless you make a separate folder with just that one test file in it, right?

See above.

Where are the TOCs stored? In a newly created file?

The TOC is generated in the shell, you can copy paste it at the top of the file.

@DutchPete
Copy link

This is my set-up.
I ran the script, python mdown_toc.py, which seems to go well.

Now, when you say "The TOC is generated in the shell, you can copy paste it at the top of the file", I assume by "shell" you mean the terminal, but it is not there.

This is what the terminal shows after running the script:

Last login: Sat Jul  4 13:04:38 on ttys000
Peters-MacBook-Air:~ peter$ cd /Volumes/NO\ NAME/Test
Peters-MacBook-Air:Test peter$ python mdown_toc.py
usage: mdown_toc.py [-h] markdown_file

Generate TOC for a markdown file.

positional arguments:
  markdown_file  Markdown file

optional arguments:
  -h, --help     show this help message and exit
Peters-MacBook-Air:Test peter$ 

as I showed in my previous reply.

So, what is not working?

@jg-you
Copy link
Author

jg-you commented Jul 7, 2020 via email

@DutchPete
Copy link

Many thanks, that worked.

In my case, running ./mdown_toc.py does not work, but python mdown_toc.py does.
Thanks also for your patience.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment