Skip to content

Commit

Permalink
add html_pygments and more options to tables
Browse files Browse the repository at this point in the history
  • Loading branch information
http://jneen.net/ committed Dec 23, 2015
1 parent a814922 commit f287925
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 34 deletions.
1 change: 1 addition & 0 deletions lib/rouge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def highlight(text, lexer, formatter, &b)
load load_dir.join('rouge/formatter.rb')
load load_dir.join('rouge/formatters/html.rb')
load load_dir.join('rouge/formatters/html_table.rb')
load load_dir.join('rouge/formatters/html_pygments.rb')
load load_dir.join('rouge/formatters/html_legacy.rb')
load load_dir.join('rouge/formatters/terminal256.rb')
load load_dir.join('rouge/formatters/null.rb')
Expand Down
32 changes: 13 additions & 19 deletions lib/rouge/formatters/html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ module Formatters
class HTML < Formatter
tag 'html'

# @option opts [String] :css_class ('highlight')
# @option opts [true/false] :line_numbers (false)
# @option opts [Rouge::CSSTheme] :inline_theme (nil)
# @option opts [true/false] :wrap (true)
Expand All @@ -24,36 +23,31 @@ class HTML < Formatter
# Content will be wrapped in a tag (`div` if tableized, `pre` if
# not) with the given `:css_class` unless `:wrap` is set to `false`.
def initialize(opts={})
@css_class = opts.fetch(:css_class, 'highlight')
@css_class = " class=#{@css_class.inspect}" if @css_class

@inline_theme = opts.fetch(:inline_theme, nil)
@inline_theme = Theme.find(@inline_theme).new if @inline_theme.is_a? String

@wrap = opts.fetch(:wrap, true)
end

# @yield the html output.
def stream(tokens, &b)
yield "<pre#@css_class><code>" if @wrap
tokens.each{ |tok, val| span(tok, val, &b) }
yield "</code></pre>\n" if @wrap
tokens.each { |tok, val| yield span(tok, val) }
end

def span(tok, val)
val = val.gsub(/[&<>]/, TABLE_FOR_ESCAPE_HTML)
shortname = tok.shortname or raise "unknown token: #{tok.inspect} for #{val.inspect}"
safe_span(tok, val.gsub(/[&<>]/, TABLE_FOR_ESCAPE_HTML))
end

def safe_span(tok, safe_val)
if tok == Token::Tokens::Text
safe_val
elsif @inline_theme
rules = @inline_theme.style_for(tok).rendered_rules

if shortname.empty?
yield val
"<span style=\"#{rules.to_a.join(';')}\">#{safe_val}</span>"
else
if @inline_theme
rules = @inline_theme.style_for(tok).rendered_rules
shortname = tok.shortname \
or raise "unknown token: #{tok.inspect} for #{safe_val.inspect}"

yield "<span style=\"#{rules.to_a.join(';')}\">#{val}</span>"
else
yield "<span class=\"#{shortname}\">#{val}</span>"
end
"<span class=\"#{shortname}\">#{safe_val}</span>"
end
end

Expand Down
4 changes: 3 additions & 1 deletion lib/rouge/formatters/html_legacy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class HTMLLegacy < Formatter
# Content will be wrapped in a tag (`div` if tableized, `pre` if
# not) with the given `:css_class` unless `:wrap` is set to `false`.
def initialize(opts={})
@formatter = opts[:line_numbers] ? HTMLTable.new(opts) : HTML.new(opts)
@formatter = opts[:line_numbers] ? HTMLTable.new(opts)
: opts[:css_class] ? HTMLPygments.new(opts)
: HTML.new(opts)
end

# @yield the html output.
Expand Down
16 changes: 16 additions & 0 deletions lib/rouge/formatters/html_pygments.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Rouge
module Formatters
class HTMLPygments < HTML
def initialize(opts)
@css_class = opts.fetch(:css_class, 'codehilite')
super
end

def stream(tokens, &b)
yield %<<pre class="#@css_class"><code>>
super
yield "</code></pre>"
end
end
end
end
28 changes: 18 additions & 10 deletions lib/rouge/formatters/html_table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@ class HTMLTable < HTML

def initialize(opts={})
@start_line = opts.fetch(:start_line, 1)
@line_format = opts.fetch(:line_format, '%i')
@table_class = opts.fetch(:table_class, 'rouge-table')
@gutter_class = opts.fetch(:gutter_class, 'rouge-gutter')
@code_class = opts.fetch(:code_class, 'rouge-code')
super
end

def style(scope)
yield "#{scope} .rouge-table { border-spacing: 0 }"
yield "#{scope} .rouge-gutter { text-align: right }"
end

def stream(tokens, &b)
num_lines = 0
last_val = ''
Expand All @@ -28,25 +37,24 @@ def stream(tokens, &b)
end

# generate a string of newline-separated line numbers for the gutter>
numbers = %<<pre class="lineno">#{(@start_line..num_lines+@start_line-1)
.to_a.join("\n")}</pre>>
formatted_line_numbers = (@start_line..num_lines+@start_line-1).map do |i|
sprintf("#{@line_format}", i) << "\n"
end.join('')

yield "<div#@css_class>" if @wrap
yield '<table style="border-spacing: 0"><tbody><tr>'
numbers = %<<pre class="lineno">#{formatted_line_numbers}</pre>>

yield %<<table class="#@table_class"><tbody><tr>>

# the "gl" class applies the style for Generic.Lineno
yield '<td class="gutter gl" style="text-align: right">'
yield %<<td class="#@gutter_class gl">>
yield numbers
yield '</td>'

yield '<td class="code">'
yield '<pre>'
yield %<<td class="#@code_class"><pre>>
yield formatted
yield '</pre>'
yield '</td>'
yield '</pre></td>'

yield "</tr></tbody></table>\n"
yield "</div>\n" if @wrap
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rouge/plugins/redcarpet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def block_code(code, language)

# override this method for custom formatting behavior
def rouge_formatter(lexer)
Formatters::HTML.new(:css_class => "highlight #{lexer.tag}")
Formatters::HTMLPygments.new(:css_class => "highlight #{lexer.tag}")
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/formatters/html_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

it 'formats a simple token stream' do
out = subject.format([[Token['Name'], 'foo']])
assert { out == %(<pre class="highlight"><code><span class="n">foo</span></code></pre>\n) }
assert { out == %(<span class="n">foo</span>) }
end

describe 'skipping the wrapper' do
let(:options) { { :wrap => false } }
let(:subject) { Rouge::Formatters::HTML.new }
let(:output) { subject.format([[Token['Name'], 'foo']]) }

it 'skips the wrapper' do
Expand Down Expand Up @@ -44,7 +44,7 @@ class InlineTheme < Rouge::CSSTheme
let(:line_numbers) { output[%r[<pre class="lineno".*?</pre>]m].scan(/\d+/m).size }

let(:output_code) {
output =~ %r(<td class="code">(.*?)</td>)m
output =~ %r(<td.*?>(.*?)</td>)m
$1
}

Expand Down

0 comments on commit f287925

Please sign in to comment.