Chris@210: module CodeRay Chris@210: module Scanners Chris@210: Chris@210: load :html Chris@210: load :ruby Chris@210: Chris@210: # RHTML Scanner Chris@210: class RHTML < Scanner Chris@210: Chris@210: include Streamable Chris@210: register_for :rhtml Chris@210: title 'HTML ERB Template' Chris@210: Chris@210: KINDS_NOT_LOC = HTML::KINDS_NOT_LOC Chris@210: Chris@210: ERB_RUBY_BLOCK = / Chris@210: <%(?!%)[=-]? Chris@210: (?> Chris@210: [^\-%]* # normal* Chris@210: (?> # special Chris@210: (?: %(?!>) | -(?!%>) ) Chris@210: [^\-%]* # normal* Chris@210: )* Chris@210: ) Chris@210: (?: -?%> )? Chris@210: /x Chris@210: Chris@210: START_OF_ERB = / Chris@210: <%(?!%) Chris@210: /x Chris@210: Chris@210: private Chris@210: Chris@210: def setup Chris@210: @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true Chris@210: @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true Chris@210: end Chris@210: Chris@210: def reset_instance Chris@210: super Chris@210: @html_scanner.reset Chris@210: end Chris@210: Chris@210: def scan_tokens tokens, options Chris@210: Chris@210: until eos? Chris@210: Chris@210: if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_until(/\z/)) and not match.empty? Chris@210: @html_scanner.tokenize match Chris@210: Chris@210: elsif match = scan(/#{ERB_RUBY_BLOCK}/o) Chris@210: start_tag = match[/\A<%[-=#]?/] Chris@210: end_tag = match[/-?%?>?\z/] Chris@210: tokens << [:open, :inline] Chris@210: tokens << [start_tag, :inline_delimiter] Chris@210: code = match[start_tag.size .. -1 - end_tag.size] Chris@210: if start_tag == '<%#' Chris@210: tokens << [code, :comment] Chris@210: else Chris@210: @ruby_scanner.tokenize code Chris@210: end Chris@210: tokens << [end_tag, :inline_delimiter] unless end_tag.empty? Chris@210: tokens << [:close, :inline] Chris@210: Chris@210: else Chris@210: raise_inspect 'else-case reached!', tokens Chris@210: end Chris@210: Chris@210: end Chris@210: Chris@210: tokens Chris@210: Chris@210: end Chris@210: Chris@210: end Chris@210: Chris@210: end Chris@210: end