For now, I'm using redcarpet as markdown preprocessor for this blog. Last week I started to write long post with many headers and wanted to add a table of contents. It seems like kramdown preprocessor supports it out of the box, but redcarpet isn't. In this post I'll show the solution.
There is many javascript-based hand-made solutions for redcarpet based on with_toc_data
extension (example). They usually works in browser but I'd like to have a solution which will generate HTML table of contents during jekyll build
command.
I found that redcarpet already supports TOC generation using Redcarpet::Render::HTML_TOC
renderer, but there is no such support in jekyll. There are several issues on GitHub dedicated to table of contents generation in jekyll. All of them was closed with message won't be implemented because it can be done with current API. This last comment with broken draft implementation pushed me to find solution on my own.
Generator
Because of Redcarpet::Render::HTML_TOC
renderer works with plain markdown input only, we need to write a Jekyll's Generator. Generator'll run before the site is generated. I wrote simple generator:
require 'redcarpet'
module Jekyll
class TocGenerator < Generator
safe true
def generate(site)
toc_render = Redcarpet::Render::HTML_TOC.new(nesting_level: 3)
parser = Redcarpet::Markdown.new(toc_render, fenced_code_blocks: true)
site.posts.docs
.find_all {|post| post.content.include?('{:toc}')}
.each do |post|
toc = parser.render(post.content)
post.content.gsub! '{:toc}', toc
end
end
end
end
You can put this toc_generator.rb
file into _plugins
folder of your jekyll-based blog.
With this generator in place you can write {:toc}
tag in your posts and it will be replaced with actual table of contents according to headings. If you wants to disable table of contents generation for specific post, just set noToc: true
in post's YAML front matter.
Happy writing!
Comments