1# -*- mode:ruby; indent-tabs-mode:nil; coding:utf-8 -*-
2#
3#  ripper_decorator.rb
4#  CocoaRepl
5#
6#  Created by Fujimoto Hisa on 07/03/01.
7#  Copyright (c) 2007 Fujimoto Hisa. All rights reserved.
8#
9require 'decorator'
10require 'langscan/ruby/compat/ripper'
11
12class RipperStyle < DecoratorStyle
13  install :ripper
14
15  style :comment,   :color => :darkGrayColor, :italic => true
16  style :keyword,   :color => :redColor,      :bold   => true
17  style :kw,        :color => :redColor,      :bold   => true # Ripper
18  style :method,    :color => '#077'
19  style :const,     :color => '#074' # Ripper
20  style :class,     :color => '#074'
21  style :module,    :color => '#050'
22  style :punct,     :color => '#447'
23  style :symbol,    :color => '#099'
24  style :string,    :color => '#944', :background => '#FFE'
25  style :char,      :color => '#F07'
26  style :ident,     :color => '#004'
27  style :constant,  :color => '#07F'
28  style :regexp,    :color => '#B66', :background => '#FEF' # Ripper
29  style :regex,     :color => '#B66', :background => '#FEF'
30  style :number,    :color => '#F99'
31  style :int,       :color => '#F99' # Ripper
32  style :float,     :color => '#F99' # Ripper
33  style :attribute, :color => '#7BB'
34  style :global,    :color => '#7FB'
35  style :expr,      :color => '#227'
36  style :escape,    :color => '#277'
37end
38
39class RipperDecorator < Decorator
40  install :ripper
41
42  def RipperDecorator.instance
43    @instance = new if not defined? @instance
44    @instance
45  end
46
47  def initialize(style = :ripper)
48    super(style)
49  end
50
51  private
52
53  KWDMAP = {
54    :symbeg      => :symbol,
55    :regexp_beg  => :regexp,
56    :tstring_beg => :string,
57    :heredoc_beg => :string,
58    :qwords_beg  => :string,
59    :words_beg   => :string,
60  }
61
62  def _key_(k) KWDMAP[k] || k end
63
64  def each_token(source)
65    regions = []
66    Ripper.lex(source).each do |ary, kwd, val|
67      token = nil
68      kwd = kwd.to_s.sub(/^on_/,'').to_sym
69
70      case kwd
71      when :symbeg then
72        regions.push( [Decorator::Token.new(_key_(kwd), val)] )
73
74      when :tstring_beg, :heredoc_beg, :qwords_beg, :words_beg, :regexp_beg then
75        regions.push( [Decorator::Token.new(_key_(kwd), val)] )
76
77      when :tstring_end, :heredoc_end, :regexp_end then
78        tokens = regions.pop
79        token = tokens.shift
80        token.value = tokens.inject(token.value) { |p,tkn| p << tkn.value }
81        token.value << val
82
83      when :ident then
84        if regions.empty? then
85          token = Decorator::Token.new(_key_(kwd), val)
86        else
87          last = regions.last
88          if last.size == 1 and last.first.kind == :symbol then
89            token = regions.pop.shift
90            token.value << val
91          else
92            regions.last.push( Decorator::Token.new(_key_(kwd), val) )
93          end
94        end
95
96      else
97        if regions.empty? then
98          token = Decorator::Token.new(_key_(kwd), val)
99        else
100          regions.last.push( Decorator::Token.new(_key_(kwd), val) )
101        end
102      end
103      yield(token) if token
104    end
105  end
106end
107