Skip to content

Instantly share code, notes, and snippets.

@jg-you

jg-you/mdown_toc.py

Last active Jul 7, 2020
Embed
What would you like to do?
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

This comment has been minimized.

Copy link
Owner Author

@jg-you jg-you commented Mar 19, 2016

Probably not robust, but it works for me.

@DutchPete

This comment has been minimized.

Copy link

@DutchPete DutchPete commented Jul 3, 2020

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

This comment has been minimized.

Copy link
Owner Author

@jg-you 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

This comment has been minimized.

Copy link

@DutchPete DutchPete commented Jul 3, 2020

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

This comment has been minimized.

Copy link

@DutchPete DutchPete commented Jul 4, 2020

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

This comment has been minimized.

Copy link
Owner Author

@jg-you 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

This comment has been minimized.

Copy link

@DutchPete DutchPete commented Jul 7, 2020

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

This comment has been minimized.

Copy link
Owner Author

@jg-you jg-you commented Jul 7, 2020

@DutchPete

This comment has been minimized.

Copy link

@DutchPete DutchPete commented Jul 7, 2020

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
You can’t perform that action at this time.