require 'cgi' module Rouge module Formatters class HTMLGitlab < Rouge::Formatter tag 'html_gitlab' # Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance. # # [+cssclass+] CSS class for the wrapping <tt><div></tt> tag # (default: 'highlight'). # [+lineanchors+] If set to true the formatter will wrap each output # line in an anchor tag with a name of L-linenumber. # This allows easy linking to certain lines # (default: false). # [+lineanchorsid+] If lineanchors is true the name of the anchors can # be changed with lineanchorsid to e.g. foo-linenumber # (default: 'L'). def initialize( cssclass: 'highlight', lineanchors: false, lineanchorsid: 'L' ) @cssclass = cssclass @lineanchors = lineanchors @lineanchorsid = lineanchorsid end def render(tokens) data = process_tokens(tokens) wrap_lines(data[:code]) end alias_method :format, :render private def process_tokens(tokens) rendered = [] current_line = '' tokens.each do |tok, val| # In the case of multi-line values (e.g. comments), we need to apply # styling to each line since span elements are inline. val.lines.each do |line| stripped = line.chomp current_line << span(tok, stripped) if line.end_with?("\n") rendered << current_line current_line = '' end end end # Add leftover text rendered << current_line if current_line.present? { code: rendered } end def wrap_lines(lines) if @lineanchors lines = lines.each_with_index.map do |line, index| number = index + @linenostart "<span id=\"#{@lineanchorsid}#{number}\" class=\"line\">#{line}" \ '</span>' end end lines.join("\n") end def span(tok, val) # http://stackoverflow.com/a/1600584/2587286 val = CGI.escapeHTML(val) if tok.shortname.empty? val else "<span class=\"#{tok.shortname}\">#{val}</span>" end end end end end