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 = Regexp.last_match(1).downcase
    @highlight_options = {}
    if defined?(Regexp.last_match(2)) && Regexp.last_match(2) != ''
      # Split along 3 possible forms -- key="<quoted list>", key=value, or key
      Regexp.last_match(2).scan(/(?:\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
        @highlight_options[key.to_sym] = value || true
      end
    end
    @highlight_options[:linenos] = "inline" if @highlight_options.key?(:linenos) && @highlight_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



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

def add_code_tag(code)
  code_attributes = [
    "class=\"language-#{@lang.to_s.tr('+', '-')}\"",
    "data-lang=\"#{@lang}\""
  ].join(" ")
  "<figure class=\"highlight\"><pre><code #{code_attributes}>#{code.chomp}</code></pre></figure>"
end

#render(context) ⇒ Object



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

def render(context)
  prefix = context["highlighter_prefix"] || ""
  suffix = context["highlighter_suffix"] || ""
  code = super.to_s.gsub(/\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

#render_codehighlighter(code) ⇒ Object



107
108
109
# File 'lib/jekyll/tags/highlight.rb', line 107

def render_codehighlighter(code)
  h(code).strip
end

#render_pygments(code, is_safe) ⇒ Object



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

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 "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.sub('<div class="highlight"><pre>', '').sub('</pre></div>', '')
end

#render_rouge(code) ⇒ Object



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

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

#sanitized_opts(opts, is_safe) ⇒ Object



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

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