1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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)
|