Class: Jekyll::Tags::HighlightBlock

Inherits:
Liquid::Block
  • Object
show all
Includes:
Liquid::StandardFilters
Defined in:
lib/jekyll/tags/highlight.rb

Constant Summary collapse

SYNTAX =

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

/^([a-zA-Z0-9.+#-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$/

Instance Method Summary collapse

Constructor Details

#initialize(tag_name, markup, tokens) ⇒ HighlightBlock

Returns a new instance of HighlightBlock.



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
# File 'lib/jekyll/tags/highlight.rb', line 13

def initialize(tag_name, markup, tokens)
  super
  if markup.strip =~ SYNTAX
    @lang = $1.downcase
    @options = {}
    if defined?($2) && $2 != ''
      # Split along 3 possible forms -- key="<quoted list>", key=value, or key
      $2.scan(/(?:\w="[^"]*"|\w=\w|\w)+/) do |opt|
        key, value = opt.split('=')
        # If a quoted list, convert to array
        if value && value.include?("\"")
            value.gsub!(/"/, "")
            value = value.split
        end
        @options[key.to_sym] = value || true
      end
    end
    @options[:linenos] = "inline" if @options.key?(:linenos) and @options[:linenos] == true
  else
    raise SyntaxError.new <<-eos
Syntax Error in tag 'highlight' while parsing the following markup:

  #{markup}

Valid syntax: highlight <lang> [linenos]
eos
  end
end

Instance Method Details

#add_code_tag(code) ⇒ Object



113
114
115
116
117
118
# File 'lib/jekyll/tags/highlight.rb', line 113

def add_code_tag(code)
  # Add nested <code> tags to code blocks
  code = code.sub(/<pre>\n*/,'<pre><code class="language-' + @lang.to_s.gsub("+", "-") + '" data-lang="' + @lang.to_s + '">')
  code = code.sub(/\n*<\/pre>/,"</code></pre>")
  code.strip
end

#render(context) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/jekyll/tags/highlight.rb', line 42

def render(context)
  prefix = context["highlighter_prefix"] || ""
  suffix = context["highlighter_suffix"] || ""
  code = super.to_s.strip

  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

#render_codehighlighter(code) ⇒ Object



109
110
111
# File 'lib/jekyll/tags/highlight.rb', line 109

def render_codehighlighter(code)
  "<div class=\"highlight\"><pre>#{h(code).strip}</pre></div>"
end

#render_pygments(code, is_safe) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/jekyll/tags/highlight.rb', line 76

def render_pygments(code, is_safe)
  require 'pygments'

  @options[:encoding] = 'utf-8'

  highlighted_code = Pygments.highlight(
    code,
    :lexer   => @lang,
    :options => sanitized_opts(@options, is_safe)
  )

  if highlighted_code.nil?
    Jekyll.logger.error "There was an error highlighting your code:"
    puts
    Jekyll.logger.error code
    puts
    Jekyll.logger.error "While attempting to convert the above code, Pygments.rb" +
      " returned an unacceptable value."
    Jekyll.logger.error "This is usually a timeout problem solved by running `jekyll build` again."
    raise ArgumentError.new("Pygments.rb returned an unacceptable value when attempting to highlight some code.")
  end

  highlighted_code
end

#render_rouge(code) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/jekyll/tags/highlight.rb', line 101

def render_rouge(code)
  require 'rouge'
  formatter = Rouge::Formatters::HTML.new(line_numbers: @options[:linenos], wrap: false)
  lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText
  code = formatter.format(lexer.lex(code))
  "<div class=\"highlight\"><pre>#{code}</pre></div>"
end

#sanitized_opts(opts, is_safe) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/jekyll/tags/highlight.rb', line 62

def sanitized_opts(opts, is_safe)
  if is_safe
    Hash[[
      [:startinline, opts.fetch(:startinline, nil)],
      [:hl_linenos,  opts.fetch(:hl_linenos, 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