module CodeRay
module Encoders
# = HTML Encoder
#
# This is CodeRay's most important highlighter:
# It provides save, fast XHTML generation and CSS support.
#
# == Usage
#
# require 'coderay'
# puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page
# puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) #-> Some /code/
# puts CodeRay.scan('Some /code/', :ruby).span #-> the same
#
# puts CodeRay.scan('Some code', :ruby).html(
# :wrap => nil,
# :line_numbers => :inline,
# :css => :style
# )
# #-> 1 Some code
#
# == Options
#
# :tab_width:: Convert \t characters to +n+ spaces (a number.)
# Default: 8
# :css:: How to include the styles; can be :class or :style.
# Default: :class
# :wrap:: Wrap in :page, :div, :span or nil.
# Default: :page
# You can also use Encoders::Div and Encoders::Span.
# :line_numbers:: Include line numbers in :table, :inline or nil (no line numbers)
# Default: nil
# :line_number_start: Where to start with line number counting.
# Default: 1
# :bold_every:: Make every +n+-th number appear bold.
# Default: 10
# :hint:: Include some information into the output using the title attribute.
# Can be :info (show token type on mouse-over) or :debug.
# Default: false
class HTML < Encoder
include Streamable
register_for :html
FILE_EXTENSION = 'html'
DEFAULT_OPTIONS = {
:tab_width => 8,
:level => :xhtml,
:css => :class,
:wrap => :page,
:line_numbers => nil,
:line_number_start => 1,
:bold_every => 10,
:hint => false,
}
require 'coderay/encoders/helpers/html_helper'
require 'coderay/encoders/helpers/html_output'
require 'coderay/encoders/helpers/html_css'
def initialize(*)
super
@last_options = nil
end
protected
HTML_ESCAPE = { #:nodoc:
'&' => '&',
'"' => '"',
'>' => '>',
'<' => '<',
}
# This is to prevent illegal HTML.
# Strange chars should still be avoided in codes.
evil_chars = Array(0x00...0x20) - [?n, ?t]
evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' }
ansi_chars = Array(0x7f..0xff)
ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '%d;' % i }
# \x9 (\t) and \xA (\n) not included
HTML_ESCAPE_PATTERN = /[&"><\0-\x8\xB-\x1f\x7f-\xff]/
def setup options
super
return if options == @last_options
@last_options = options
@HTML_ESCAPE = HTML_ESCAPE.dup
@HTML_ESCAPE["\t"] = ' ' * options[:tab_width]
@opened = [nil]
@css = CSS.new
hint = options[:hint]
raise ArgumentError if hint and not [:debug, :info].include? hint
case options[:css]
when :class
@css_style = Hash.new do |h, k|
if k.is_a? Array
type = k.first
else
type = k
end
c = ClassOfKind[type]
if c == :NO_HIGHLIGHT and not hint
h[k] = false
else
title = if hint
if hint == :debug
' title="%p"' % [ k ]
elsif hint == :info and k.size == 1
" title=\"#{type.to_s.gsub(/_/, " ").capitalize}\""
end
else
''
end
h[k] = '' % [title, c]
end
end
when :style
@css_style = Hash.new do |h, k|
if k.is_a? Array
styles = k.dup
else
styles = [k]
end
type = styles.first
styles.map! { |c| ClassOfKind[c] }
if styles.first == :NO_HIGHLIGHT and not hint
h[k] = false
else
title = if hint
if hint == :debug
' title="%p"' % [ styles ]
elsif hint == :info and styles.size == 1
" title=\"#{type.to_s.gsub(/_/, " ").capitalize}\""
end
else
''
end
style = @css[*styles]
h[k] =
if style
'' % [title, style]
else
false
end
end
end
else
raise "Unknown value %p for :css." % options[:css]
end
end
def finish options
not_needed = @opened.shift
@out << '' * @opened.size
@out.extend Output
@out.numerize! options[:line_numbers], options # if options[:line_numbers]
@out.wrap! options[:wrap] # if options[:wrap]
#require 'pp'
#pp @css_style, @css_style.size
super
end
def token text, type
if text.is_a? String
if text =~ /#{HTML_ESCAPE_PATTERN}/o
text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] }
end
@opened[0] = type
style = @css_style[@opened]
if style
@out << style << text << ''
else
@out << text
end
else
case text
when :open
@opened[0] = type
@out << @css_style[@opened]
@opened << type
when :close
unless @opened.empty?
raise 'Not Token to be closed.' unless @opened.size > 1
@out << ''
@opened.pop
end
when nil
raise 'Token with nil as text was given: %p' % [[text, type]]
else
raise 'unknown token kind: %p' % text
end
end
end
end
end
end