]> git.notmuchmail.org Git - sup/blob - lib/sup/colormap.rb
add buffer search with '/' and 'n', and change index search to '\'
[sup] / lib / sup / colormap.rb
1 module Redwood
2
3 class Colormap
4   @@instance = nil
5
6   CURSES_COLORS = [Curses::COLOR_BLACK, Curses::COLOR_RED, Curses::COLOR_GREEN,
7                    Curses::COLOR_YELLOW, Curses::COLOR_BLUE,
8                    Curses::COLOR_MAGENTA, Curses::COLOR_CYAN,
9                    Curses::COLOR_WHITE]
10   NUM_COLORS = 15
11   
12   def initialize
13     raise "only one instance can be created" if @@instance
14     @@instance = self
15     @entries = {}
16     @color_pairs = {[Curses::COLOR_WHITE, Curses::COLOR_BLACK] => 0}
17     @users = []
18     @next_id = 0
19     yield self if block_given?
20     @entries[highlight_sym(:none)] = highlight_for(Curses::COLOR_WHITE,
21                                                    Curses::COLOR_BLACK,
22                                                    []) + [nil]
23   end
24
25   def add sym, fg, bg, attr=nil, opts={}
26     raise ArgumentError, "color for #{sym} already defined" if @entries.member? sym
27     raise ArgumentError, "color '#{fg}' unknown" unless CURSES_COLORS.include? fg
28     raise ArgumentError, "color '#{bg}' unknown" unless CURSES_COLORS.include? bg
29     attrs = [attr].flatten.compact
30
31     @entries[sym] = [fg, bg, attrs, nil]
32     @entries[highlight_sym(sym)] = opts[:highlight] ? @entries[opts[:highlight]] : highlight_for(fg, bg, attrs) + [nil]
33   end
34
35   def highlight_sym sym
36     "#{sym}_highlight".intern
37   end
38
39   def highlight_for fg, bg, attrs
40     hfg =
41       case fg
42       when Curses::COLOR_BLUE
43         Curses::COLOR_WHITE
44       when Curses::COLOR_YELLOW, Curses::COLOR_GREEN
45         fg
46       else
47         Curses::COLOR_BLACK
48       end
49
50     hbg = 
51       case bg
52       when Curses::COLOR_CYAN
53         Curses::COLOR_YELLOW
54       else
55         Curses::COLOR_CYAN
56       end
57
58     attrs =
59       if fg == Curses::COLOR_WHITE && attrs.include?(Curses::A_BOLD)
60         [Curses::A_BOLD]
61       else
62         case hfg
63         when Curses::COLOR_BLACK
64           []
65         else
66           [Curses::A_BOLD]
67         end
68       end
69     [hfg, hbg, attrs]
70   end
71
72   def color_for sym, highlight=false
73     sym = highlight_sym(sym) if highlight
74     return Curses::COLOR_BLACK if sym == :none
75     raise ArgumentError, "undefined color #{sym}" unless @entries.member? sym
76
77     ## if this color is cached, return it
78     fg, bg, attrs, color = @entries[sym]
79     return color if color
80
81     if(cp = @color_pairs[[fg, bg]])
82       ## nothing
83     else ## need to get a new colorpair
84       @next_id = (@next_id + 1) % NUM_COLORS
85       @next_id += 1 if @next_id == 0 # 0 is always white on black
86       id = @next_id
87       Redwood::log "colormap: for color #{sym}, using id #{id} -> #{fg}, #{bg}"
88       Curses.init_pair id, fg, bg or raise ArgumentError,
89         "couldn't initialize curses color pair #{fg}, #{bg} (key #{id})"
90
91       cp = @color_pairs[[fg, bg]] = Curses.color_pair(id)
92       ## delete the old mapping, if it exists
93       if @users[cp]
94         @users[cp].each do |usym|
95           Redwood::log "dropping color #{usym} (#{id})"
96           @entries[usym][3] = nil
97         end
98         @users[cp] = []
99       end
100     end
101
102     ## by now we have a color pair
103     color = attrs.inject(cp) { |color, attr| color | attr }
104     @entries[sym][3] = color # fill the cache
105     (@users[cp] ||= []) << sym # record entry as a user of that color pair
106     color
107   end
108
109   def self.instance; @@instance; end
110   def self.method_missing meth, *a
111     Colorcolors.new unless @@instance
112     @@instance.send meth, *a
113   end
114 end
115
116 end