summaryrefslogtreecommitdiff
path: root/src/_plugins/highlight.rb
diff options
context:
space:
mode:
Diffstat (limited to 'src/_plugins/highlight.rb')
-rw-r--r--src/_plugins/highlight.rb127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/_plugins/highlight.rb b/src/_plugins/highlight.rb
new file mode 100644
index 0000000..d59140c
--- /dev/null
+++ b/src/_plugins/highlight.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+module Jekyll
+ module Tags
+ class HighlightBlock < Liquid::Block
+ include Liquid::StandardFilters
+
+ def initialize(tag_name, markup, tokens)
+ super
+
+ opts = markup.split
+ @opts = Hash.new
+ @lang = opts.shift.downcase
+
+ opts.each do |opt|
+ if opt.include?("=")
+ parts = opt.split("=", 2)
+
+ @opts[parts[0]] = parts[1]
+ end
+
+ @opts[opt] = true
+ 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)],
+ ].reject { |f| f.last.nil? }]
+ else
+ opts
+ end
+ end
+
+ private
+
+ def render_pygments(code, is_safe)
+ Jekyll::External.require_with_graceful_fail("pygments") unless defined?(Pygments)
+
+ highlighted_code = Pygments.highlight(
+ code,
+ :lexer => @lang,
+ :options => sanitized_opts(@highlight_options, is_safe)
+ )
+
+ if highlighted_code.nil?
+ Jekyll.logger.error <<~MSG
+ 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.
+ MSG
+ 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)
+ require "rouge"
+ formatter = ::Rouge::Formatters::HTMLLegacy.new(
+ :line_numbers => @highlight_options[:linenos],
+ :wrap => false,
+ :css_class => "highlight",
+ :gutter_class => "gutter",
+ :code_class => "code"
+ )
+ 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(" ")
+
+ output = "<figure class=\"highlight\"><pre><code #{code_attributes}>"
+ output += code.chomp
+ output += "</code></pre>"
+
+ if @opts["tio"]
+ output += "<div class=\"code-link\"><a href=\"#{@opts["tio"]}\" target=\"_blank\">Run this code</a></div>"
+ end
+
+ output += "</figure>"
+
+ output
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag("highlight", Jekyll::Tags::HighlightBlock)