Skip to content

Instantly share code, notes, and snippets.

@chriscasola
Last active June 13, 2022 08:30
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save chriscasola/4700426 to your computer and use it in GitHub Desktop.
Save chriscasola/4700426 to your computer and use it in GitHub Desktop.
A python script to generate a table of contents for a GitHub Flavored markdown file. The file must contain a level one header with a title that contains "Table of Contents". The script will generate a TOC containing all level 1, 2, and 3 headers.
A python script to generate a table of contents (with links) for a GitHub Flavored markdown file.
The file must contain a level one header with a title that contains "Table of Contents".
The script will generate a TOC containing all level 1, 2, and 3 headers.
Run the script like this:
python tocgen.py inFileName outFileName
BEFORE file:
--------------------------------------------------------
This is my GitHub wiki page.
# Table of Contents
There can be an old TOC here, it's ok.
# First header
bla
## Second header
bla bla
# Third header
bla
---------------------------------------------------------
AFTER file:
---------------------------------------------------------
# Table of Contents
* [First header]($s1)
* [Second header](#s1-1)
* [Third header]($s2)
# <a id='s1' />First header
bla
## <a id='s1-1' />Second header
bla bla
# <a id='s2' />Third header
bla
def processFile(inFile, outFile):
mdFile = open(inFile, 'r')
toc = []
levels = [0,0,0,0]
newFile = open(outFile, 'w')
tempFile = []
tocLoc = 0
partOfToc = False
for line in mdFile:
if partOfToc and line != '\n':
continue
else:
partOfToc = False
if 'Table of Contents' in line:
tocLoc = len(tempFile) + 1
partOfToc = True
elif line[0] == '#':
secId = buildToc(line, toc, levels)
line = addSectionTag(cleanLine(line), secId) + '\n'
tempFile.append(line)
for line in toc:
tempFile.insert(tocLoc, line)
tocLoc += 1
for line in tempFile:
newFile.write(line)
mdFile.close()
newFile.close()
def addSectionTag(line, secId):
startIndex = line.find(' ')
line = line[:startIndex + 1] + '<a id=\'' + secId + '\' />' + line[startIndex + 1:]
return line
def buildToc(line, toc, levels):
line = cleanLine(line)
secId = 's'
if line[:4] == '####':
raise UserWarning('Header levels greater than 3 not supported')
elif line[:3] == '###':
levels[3] += 1
secId += str(levels[1]) + '-' + str(levels[2]) + '-' + str(levels[3])
toc.append(' * [' + line[4:] + '](#' + secId + ')\n')
elif line[:2] == '##':
levels[2] += 1
levels[3] = 0
secId += str(levels[1]) + '-' + str(levels[2])
toc.append(' * [' + line[3:] + '](#' + secId + ')\n')
elif line[:1] == '#':
levels[1] += 1
levels[3] = levels[2] = 0
secId += str(levels[1])
toc.append('* [' + line[2:] + '](#' + secId + ')\n')
return secId
def cleanLine(text):
text = stripNewline(text)
text = removeAnchors(text)
return text
def stripNewline(text):
return text.replace('\n', '')
def removeAnchors(text):
while ('<' in text and '>' in text):
leftTag = text.index('<')
rightTag = text.index('>')
text = text[0:leftTag] + text[rightTag + 1:]
return text
if __name__ == "__main__":
import sys
processFile(sys.argv[1], sys.argv[2])
@MichaelMoser1970
Copy link

I had a problem with code blocks, everything that looks like a title in a code block should not result in a table of content entry. Here is my adaptation: https://github.com/MoserMichael/python-obj-system/blob/master/tocgen.py

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