Skip to main content

Generate a table of contents from the comments of a file

Project description

toc

toc - Generate a table of contents from the comments of a file

Example table of contents generated by toc

What is it?

toc is a command line utility that generates the table of contents of a file from a special kind of comments.

Think it as a tree for the contents of a file, instead of a directory.

As a Python package, you can install it by running:

pip install tableofcontents

If you are using Arch or Manjaro Linux, you can install toc directly from the AUR.

Why should I use it?

Few reasons that you may consider:

  • it can make your files understandable in seconds, even if you haven't touched them for a while
  • you can jump directly to the section you need to edit, because you know where it's located
  • it makes you reflect about the structure of your file, making it more logical
  • for software developers, it makes your code base more readable to others

How does it work?

First, you have to write the comments representing the different sections of a file. Second, you run toc on that file to turn those comments into a table of contents.

Read the table of contents

Let's say you want to structure your javascript file "example.js". Single line comments in this language start with "//". You open your file and add these comments where you need them:

Original example.js
#!/usr/bin/env node

// ################################################################ Main section

let Section1 = "Write //, 64 hash characters and the name of section"

// ################################ Nested section

let Section2 = "Write //, 32 hash characters and the name of section"

// ################ Nested section

let Section3 = "Write //, 16 hash characters and the name of section"

// ######## Nested section

let Section4 = "Write //, 8 hash characters and the name of section"

// #### Nested section

let Section5 = "Write //, 4 hash characters and the name of section"

If you run toc example.js, the program will output the following (stdout):

// ┌───────────────────────────────────────────────────────────────┐
// │ Contents of example.js                                        │
// ├───────────────────────────────────────────────────────────────┘
// │
// ├──┐Main section
// │  └──┐Nested section
// │     └──┐Nested section
// │        └──┐Nested section
// │           └── Nested section
// │
// └───────────────────────────────────────────────────────────────

Embed the table of contents in the original file

If you want to output the toc we just saw to the file, you should run toc -f example.js and get (stderr):

Adding toc to file example.js

By opening "example.js", the file content will be:

example.js with toc
#!/usr/bin/env node

// ┌───────────────────────────────────────────────────────────────┐
// │ Contents of example.js                                        │
// ├───────────────────────────────────────────────────────────────┘
// │
// ├──┐Main section
// │  └──┐Nested section
// │     └──┐Nested section
// │        └──┐Nested section
// │           └── Nested section
// │
// └───────────────────────────────────────────────────────────────

// ################################################################ Main section

let Section1 = "Write //, 64 hash characters and the name of section"

// ################################ Nested section

let Section2 = "Write //, 32 hash characters and the name of section"

// ################ Nested section

let Section3 = "Write //, 16 hash characters and the name of section"

// ######## Nested section

let Section4 = "Write //, 8 hash characters and the name of section"

// #### Nested section

let Section5 = "Write //, 4 hash characters and the name of section"

Notice how toc recognized the shebang for node and added the table of contents after it. If you run again toc -f example.js, it recognizes that there is no need to update the toc, as no changes have been made.

However, if you add new sections to the file and run again toc -f example.js, it will update the file accordingly:

Updating toc in file example.js
Modified example.js with toc
#!/usr/bin/env node

// ┌───────────────────────────────────────────────────────────────┐
// │ Contents of example.js                                        │
// ├───────────────────────────────────────────────────────────────┘
// │
// ├──┐Main section
// │  ├──┐New section
// │  │  └── Also New section
// │  ├──┐New section
// │  │  └── Also New section
// │  └──┐Nested section
// │     └──┐Nested section
// │        └──┐Nested section
// │           └── Nested section
// │
// └───────────────────────────────────────────────────────────────

// ################################################################ Main section

let Section_1 = "Write //, 64 hash characters and the name of section"

// ################################ New section

let Section_1_1 = "Write //, 32 hash characters and the name of section"

// ################ Also New section

let Section_1_1_1 = "Write //, 32 hash characters and the name of section"

// ################################ New section

let Section_1_1 = "Write //, 32 hash characters and the name of section"

// ################ Also New section

let Section_1_1_1 = "Write //, 32 hash characters and the name of section"

// ################################ Nested section

let Section_1_2 = "Write //, 32 hash characters and the name of section"

// ################ Nested section

let Section_1_2_3 = "Write //, 16 hash characters and the name of section"

// ######## Nested section

let Section_1_2_4 = "Write //, 8 hash characters and the name of section"

// #### Nested section

let Section_1_2_5 = "Write //, 4 hash characters and the name of section"

Use a custom comment character

But how could toc recognize that "//" is the proper comment character for that file? Well, thanks to AI[^1] toc supports most programming and markup languages, including FORTRAN and Zig. In case it doesn't work as expected, you can force the behavior by running toc -c "//" example.xyz.

Show line numbers

For very long files, it may come in handy to run toc -n example.js to see the line number of each section, similar to the page numbers in the table of contents of a book:

// ┌───────────────────────────────────────────────────────────────┐
// │ Contents of example.js                                        │
// ├───────────────────────────────────────────────────────────────┘
// │
// ├──┐Main section 19
// │  ├──┐New section 23
// │  │  └── Also New section 27
// │  ├──┐New section 31
// │  │  └── Also New section 35
// │  └──┐Nested section 39
// │     └──┐Nested section 43
// │        └──┐Nested section 47
// │           └── Nested section 51
// │
// └───────────────────────────────────────────────────────────────

Batch processing

If you feel brave enough, you can run toc over your entire code base, as its AI[^2] will make it:

  • skip directories (. below)
  • skip non-text files (toc.cpython-311.pyc below)
  • skip non-existing files
  • skip non-readable files
  • skip non-writable files
  • skip files that don't have suitable "section" comments (__init__.py below)
  • skip files whose toc is already up-to-date (toc.py below)
Skipping directory .
Skipping empty "#" toc for ./__init__.py
Skipping directory ./__pycache__
Skipping binary file ./__pycache__/toc.cpython-311.pyc
Skipping replacing same toc in file ./toc.py
Updating toc in file ./cli.py
Skipping replacing same toc in file ./example.js

Additionally, you can run toc -h for usage info and toc -v to read the current version

Exceptional file types

For Markdown files, you don't need to write comments, just organize your sections with one or more "#".

For Beancount files, it's the same for Markdown, but you use "*" instead.

For CSS files, you have to wrap your "//" comments between /* and */:

example.css
/*
// ################################################################ Landscape touchscreen
*/

@media (orientation: landscape) and (hover: none) and (pointer: coarse) {

/*
// ################################ Element selectors
*/

 body {
  background-color: blue;
 }

} /* end Landscape touchscreen */

For HTML files, you have to wrap your "//" comments between <!-- and -->:

example.html
<!doctype html>
<html lang="en">

<!--
// ################################################################ Head
-->

 <head>
  <link rel="stylesheet" href="/assets/css/example.css"/>
  <script src="/assets/js/example.js"></script>
 </head>

<!--
// ################################################################ Body
-->

 <body>
  <h1>Title</h1>
 </body>
</html>

How can I contribute?

If you have a suggestion or you found an issue, you can use GitHub issues and pull requests to contribute.

What changed from previous versions?

2.0.0

  • rewritten in pure python
  • published to PyPI as tableofcontents
  • added feature to prepend the table of contents to files, preserving shebangs

1.0.0

  • initial release of toc in bash, perl, sed and awk

[^1]: No, not really, it's just a match-case statement using the file extension, defaulting to "#" [^2]: Not even, it's just a bunch of if-else and try-excepts statement that may prevent catastrophic damage

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tableofcontents-2.0.0.tar.gz (21.7 kB view hashes)

Uploaded Source

Built Distribution

tableofcontents-2.0.0-py3-none-any.whl (22.0 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page