Captioning Jekyll highlighted code block

Jekyll encloses code highlighted with {% highlight_ %} Liquid tag inside <figure> HTML tag. That in turn allows embeeding <figcaption> tag and captioning code, e.g. with file path. Jekyll (v4.3.2) does not provide captioning, but can be extended with simple plugin.

Plugin code presented here and used by this blog is here.

The plugin overrides Jekyll::Tags::HighlightBlock.render() method. HTML code returned by this method can be manipulated using parser library like Nokogiri, but inserting a single tag is simple enough to be succesfully performed without additional libraries:

RUBY:_plugins/highlight-caption-option.rb
module HighlightCaption
  ...

  def render(*args)
    caption = "<figcaption>#{@highlight_options[:caption]}</figcaption>"

    match = super.match('<figure[^>]*>')
    match.pre_match + match.to_s + caption + match.post_match
  end
end

Caption generating code can be freely modified. It can even process additional options passed to {% highlight %} tag. Options are only allowed to consist of alphanumeric characters and underscore. Passing file path as option requires loosening this restriction. We allow any non-blank character, except those used to control option format (options are allowed to be expressed as: name, name=value and name=“quoted list”)

RUBY:_plugins/highlight-caption-option.rb
module HighlightCaption
  def self.prepended(mod)
    syntax = mod.send(:remove_const, :SYNTAX).source.gsub('\\w', '[^[:^graph:]"=]')
    mod.const_set(:SYNTAX, Regexp.new(syntax))
    options = mod.send(:remove_const, :OPTIONS_REGEX).source.gsub('\\w', '[^[:^graph:]"=]')
    mod.const_set(:OPTIONS_REGEX, Regexp.new(options))
  end

  ...
end

Finally the modifications have to be prepend-ed to original class:

RUBY:_plugins/highlight-caption-option.rb
Jekyll::Hooks.register :site, :pre_render do |site|
  Jekyll::Tags::HighlightBlock.prepend JekyllTagsExtensions::HighlightCaption
end