require 'rubygems'
require 'syntax/convertors/html'
require 'syntax/lang/xml'
require 'syntax/lang/ruby'
require 'syntax/lang/yaml'
require 'syntax'
require 'redcloth'
module Zena
module Code
module DefaultSyntax
def to_html(opts = {})
code_lang = @code_lang
code_class = "#{opts[:theme] || 'idle'}_code"
if ::Syntax::SYNTAX[code_lang] != ::Syntax::Default
convertor = ::Syntax::Convertors::HTML.for_syntax(code_lang)
if opts[:inline]
"#{convertor.convert(@text, false)}
"
else
if pre_params = opts[:pre_params]
if pre_params =~ /^(.*)class\s*=\s*('|")([^\2]+)\2(.*)$/
code_class = "#{code_class} #{$3}"
pre_params = "#{$1} #{$4}"
end
tag = "
" else tag = "" end "#{tag}#{convertor.convert(@text, false)}" end else basic_to_html(opts[:inline], code_class) end end end # Syntax end # Code end module Syntax # changed 'Token' class to make recursive calls possible class Token < String # the type of the lexeme that was extracted. attr_reader :group # the instruction associated with this token (:none, :region_open, or # :region_close) attr_reader :instruction # true if this token's html tags should be escaped attr_reader :escape # Create a new Token representing the given text, and belonging to the # given group. def initialize( text, group, instruction = :none, escape = true ) super text @group = group @instruction = instruction @escape = escape end end class Tokenizer private def sub_lang( gr, data ) flush_chunk @callback.call( Token.new( data, gr, :none, false ) ) end def parse_params(text) return [] unless text params = [] rest = text.strip while (rest != '') if rest =~ /(.+?)=/ key = $1.strip.to_sym rest = rest[$&.length..-1].strip if rest =~ /('|")([^\1]*?[^\\])\1/ rest = rest[$&.length..-1].strip if $1 == "'" params << [key,$2.gsub("\\'", "'")] else params << [key,$2.gsub('\\"', '"')] end else # error, bad format, return found params. break end else # error, bad format break end end params end end # Tokenizer module Convertors # A simple class for converting a text into HTML. class HTML < Abstract # Converts the given text to HTML, using spans to represent token groups # of any type but :normal (which is always unhighlighted). If # +pre+ is +true+, the html is automatically wrapped in pre tags. def convert( text, pre=true ) html = "" html << "" if pre regions = [] @tokenizer.tokenize( text ) do |tok| value = tok.escape ? html_escape(tok) : tok case tok.instruction when :region_close then regions.pop html << "" when :region_open then regions.push tok.group html << "#{value}" else if tok.group == ( regions.last || :normal ) html << value else html << "#{value}" end end end html << "" while regions.pop html << "
" if pre html end end end # Convertors class ZafuTokenizer < Tokenizer METHOD = "[\\w]+\\??" def step if ztag = scan(/\A<\/?r:[^>]+>/) ztag =~ /<(\/?)r:(#{METHOD})([^>]*?)(\/?)>/ start_group :tag, "<#{$1}r:" start_group :ztag, $2 trailing = $4 params = parse_params($3) params.each do |k,v| append " " if v =~ /[^\\]'/ v = "\"#{v}\"" else v = "'#{v}'" end start_group :param, k.to_s append '=' start_group :value, v end start_group :tag, "#{trailing}>" elsif dotag = scan(/<(\w+)([^>]*?)do\s*=('|")([^\3]*?[^\\])\3([^>]*?)(\/?)>/) if dotag =~ /\A<(\w+)([^>]*?)do\s*=('|")([^\3]*?[^\\])\3([^>]*?)(\/?)>/ start_group :tag, "<#{$1}#{$2}" start_group :tag, "do=" start_group :ztag, "'#{$4}'" trailing = $6 params = parse_params($5) params.each do |k,v| append " " if v =~ /[^\\]'/ v = "\"#{v}\"" else v = "'#{v}'" end if k == :do start_group :tag, k.to_s append '=' start_group :ztag, v else start_group :param, k.to_s append '=' start_group :value, v end end start_group :tag, "#{trailing}>" else start_group :normal, dotag end elsif html = scan(/\A<\/?[^>]+>/) html =~/<\/?([^>]+)>/ start_group :tag, html else start_group :normal, scan(/./m) end end end # ZafuTokenizer SYNTAX['zafu'] = ZafuTokenizer class ErbTokenizer < Tokenizer def step if methods = scan(/<%[^>]+%>/m) methods =~ /<%(=?)([^>]+?)(-?)%>/m start_group :punct, "<%#{$1}" trailing = $3 sub_lang :expr, "#{Convertors::HTML.for_syntax('ruby').convert($2, false)}
" start_group :punct, "#{trailing}%>" elsif html = scan(/<\/?[^>]+>/) html =~/<\/?([^>]+)>/ start_group :tag, html else start_group :normal, scan(/./m) end end end # ErbTokenizer SYNTAX['erb'] = ErbTokenizer class CssTokenizer < Tokenizer def step if comments = scan(/\s*\/\*.*?\*\/\s*/m) start_group :comment, comments elsif variables = scan(/[^\{]*?\{[^\}]*?\}/m) variables =~ /(\s*)([^\{]*?)\{([^\}]*?)\}/m start_group :normal, $1 vars = $3 selectors = $2.split(',').map { |s| s.strip } selectors.each_index do |i| selectors[i].gsub('.','|.').gsub('#','|#').split('|').each do |g| g = g.split(' ') g.each do |s| if s[0..0] == '#' start_group :id, s elsif s[0..0] == '.' start_group :class, s else start_group :tag, s end start_group :normal, ' ' end end unless i == selectors.size - 1 start_group :punct, ', ' end end start_group :punct, '{ ' rest = vars while rest != '' && rest =~ /([\w-]+)\s*:\s*(.*?)\s*;(.*)/m start_group :variable, $1 start_group :punct, ':' start_group :normal, $2 start_group :punct, '; ' rest = $3 end start_group :punct, "#{rest}}" else start_group :normal, scan(/./m) end end end # CssTokenizer SYNTAX['css'] = CssTokenizer class ShTokenizer < Tokenizer def step if variables = scan(/\$\w+/) start_group :variable, variables elsif start = scan(/# \S+/) start_group :punct, '# ' start_group :method, start[2..-1] elsif start = scan(/\$ \S+/) start_group :root, '$ ' start_group :method, start[2..-1] else start_group :normal, scan(/./m) end end end # ShTokenizer SYNTAX['sh'] = ShTokenizer class PseudoSqlTokenizer < Tokenizer def step if @state.nil? and method = scan(/\w+/) start_group :method, method @state = :method elsif @state == :in and context = scan(/\w+/) start_group :context, context @state = :context elsif keyword = scan(/\bin\b/) start_group :context, keyword @state = :in elsif keyword = scan(/\bfrom\b/) start_group :sub, keyword @state = nil elsif keyword = scan(/\bwhere|select|group\s+by|having|order|limit|offset|paginate\b/) start_group :keyword, keyword elsif punct = scan(/\b>=|<=|<>|<|=|>|not\s+like|like|lt|le|eq|ne|ge|gt\b/) start_group :punct, punct elsif string = scan(/("|')[^'"]*\1/) string =~ /("|')([^'"]*)\1/ start_group :punct, $1 start_group :string, $2 start_group :punct, $1 else start_group :normal, scan(/./m) end end end # PseudoSqlTokenizer SYNTAX['sqliss'] = PseudoSqlTokenizer end # Syntax