Created
June 22, 2016 18:03
-
-
Save czak/94f8b98e3f6789b38a4f7414ca703380 to your computer and use it in GitHub Desktop.
Extended jekyll {% highlight %} tag with <figcaption>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Czak | |
module Tags | |
class HighlightCaptionBlock < Liquid::Block | |
include Liquid::StandardFilters | |
# The regular expression syntax checker. Start with the language specifier. | |
# Follow that by zero or more space separated options that take one of three | |
# forms: name, name=value, or name="<quoted list>" | |
# | |
# <quoted list> is a space-separated list of numbers | |
SYNTAX = %r!^([a-zA-Z0-9.+#-]+)((\s+\w+(=([\w\.\/-]+|"([0-9]+\s)*[0-9]+"))?)*)$! | |
def initialize(tag_name, markup, tokens) | |
super | |
if markup.strip =~ SYNTAX | |
@lang = Regexp.last_match(1).downcase | |
@highlight_options = parse_options(Regexp.last_match(2)) | |
else | |
raise SyntaxError, <<-eos | |
Syntax Error in tag 'highlight' while parsing the following markup: | |
#{markup} | |
Valid syntax: highlight <lang> [linenos] | |
eos | |
end | |
end | |
def render(context) | |
prefix = context["highlighter_prefix"] || "" | |
suffix = context["highlighter_suffix"] || "" | |
code = super.to_s.gsub(%r!\A(\n|\r)+|(\n|\r)+\z!, "") | |
is_safe = !!context.registers[:site].safe | |
output = | |
case context.registers[:site].highlighter | |
when "pygments" | |
render_pygments(code, is_safe) | |
when "rouge" | |
render_rouge(code) | |
else | |
render_codehighlighter(code) | |
end | |
rendered_output = add_code_tag(output) | |
prefix + rendered_output + suffix | |
end | |
def sanitized_opts(opts, is_safe) | |
if is_safe | |
Hash[[ | |
[:startinline, opts.fetch(:startinline, nil)], | |
[:hl_lines, opts.fetch(:hl_lines, nil)], | |
[:linenos, opts.fetch(:linenos, nil)], | |
[:encoding, opts.fetch(:encoding, "utf-8")], | |
[:cssclass, opts.fetch(:cssclass, nil)], | |
[:caption, opts.fetch(:caption, nil)] | |
].reject { |f| f.last.nil? }] | |
else | |
opts | |
end | |
end | |
private | |
def parse_options(input) | |
options = {} | |
unless input.empty? | |
# Split along 3 possible forms -- key="<quoted list>", key=value, or key | |
input.scan(%r!(?:\w+="[^"]*"|\w+=[\w\.\/-]+|\w+)!) do |opt| | |
key, value = opt.split("=") | |
# If a quoted list, convert to array | |
if value && value.include?("\"") | |
value.delete!('"') | |
value = value.split | |
end | |
options[key.to_sym] = value || true | |
end | |
end | |
if options.key?(:linenos) && options[:linenos] == true | |
options[:linenos] = "inline" | |
end | |
options | |
end | |
def render_pygments(code, is_safe) | |
Jekyll::External.require_with_graceful_fail("pygments") | |
highlighted_code = Pygments.highlight( | |
code, | |
:lexer => @lang, | |
:options => sanitized_opts(@highlight_options, is_safe) | |
) | |
if highlighted_code.nil? | |
Jekyll.logger.error <<eos | |
There was an error highlighting your code: | |
#{code} | |
While attempting to convert the above code, Pygments.rb returned an unacceptable value. | |
This is usually a timeout problem solved by running `jekyll build` again. | |
eos | |
raise ArgumentError, "Pygments.rb returned an unacceptable value "\ | |
"when attempting to highlight some code." | |
end | |
highlighted_code.sub('<div class="highlight"><pre>', "").sub("</pre></div>", "") | |
end | |
def render_rouge(code) | |
Jekyll::External.require_with_graceful_fail("rouge") | |
formatter = Rouge::Formatters::HTML.new( | |
:line_numbers => @highlight_options[:linenos], | |
:wrap => false | |
) | |
lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText | |
formatter.format(lexer.lex(code)) | |
end | |
def render_codehighlighter(code) | |
h(code).strip | |
end | |
def add_code_tag(code) | |
code_attributes = [ | |
"class=\"language-#{@lang.to_s.tr("+", "-")}\"", | |
"data-lang=\"#{@lang}\"" | |
].join(" ") | |
res = "<figure class=\"highlight\">" | |
res += "<figcaption>#{@highlight_options[:caption]}</figcaption>" if @highlight_options[:caption] | |
res += "<pre><code #{code_attributes}>#{code.chomp}</code></pre></figure>" | |
res | |
end | |
end | |
end | |
end | |
Liquid::Template.register_tag("highlight2", Czak::Tags::HighlightCaptionBlock) |
@mohkale Are there other means to add caption other than to a separate file?
I'm not sure what you're asking. Either way it's been nearly two years since I wrote this and well over a year since I stopped using jekyll so I'm not sure I'll be of much help.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I got annoyed by the fact that the
highlight
tag doesn't follow my kramdown settings for line numbers so I added a fallback to that when unspecified. I also got annoyed that I couldn't declare prefixes for figure captions in the tag itself, so I added that. Then I got annoyed that you can't send values with multiple spaces to the tag, noticed that you can for some reason do so with commer delimeted numbers in speech marks, also noticed that doing so is meaningless because@highlight_options
is only used for line numbers, literally nothing else; so I changed it so that you can delimit multi space strings using speech marks (doesn't support speech marks within strings sadly).Anyways, here's what I've got now: