Class: Redwood::Colormap

Inherits:
Object show all
Defined in:
lib/sup/colormap.rb

Constant Summary

CURSES_COLORS =
[Curses::COLOR_BLACK, Curses::COLOR_RED, Curses::COLOR_GREEN,
Curses::COLOR_YELLOW, Curses::COLOR_BLUE,
Curses::COLOR_MAGENTA, Curses::COLOR_CYAN,
Curses::COLOR_WHITE, Curses::COLOR_DEFAULT]
NUM_COLORS =
15
DEFAULT_COLORS =
{
  :status => { :fg => "white", :bg => "blue", :attrs => ["bold"] },
  :index_old => { :fg => "white", :bg => "default" },
  :index_new => { :fg => "white", :bg => "default", :attrs => ["bold"] },
  :index_starred => { :fg => "yellow", :bg => "default", :attrs => ["bold"] },
  :index_draft => { :fg => "red", :bg => "default", :attrs => ["bold"] },
  :labellist_old => { :fg => "white", :bg => "default" },
  :labellist_new => { :fg => "white", :bg => "default", :attrs => ["bold"] },
  :twiddle => { :fg => "blue", :bg => "default" },
  :label => { :fg => "yellow", :bg => "default" },
  :message_patina => { :fg => "black", :bg => "green" },
  :alternate_patina => { :fg => "black", :bg => "blue" },
  :missing_message => { :fg => "black", :bg => "red" },
  :attachment => { :fg => "cyan", :bg => "default" },
  :cryptosig_valid => { :fg => "yellow", :bg => "default", :attrs => ["bold"] },
  :cryptosig_unknown => { :fg => "cyan", :bg => "default" },
  :cryptosig_invalid => { :fg => "yellow", :bg => "red", :attrs => ["bold"] },
  :generic_notice_patina => { :fg => "cyan", :bg => "default" },
  :quote_patina => { :fg => "yellow", :bg => "default" },
  :sig_patina => { :fg => "yellow", :bg => "default" },
  :quote => { :fg => "yellow", :bg => "default" },
  :sig => { :fg => "yellow", :bg => "default" },
  :to_me => { :fg => "green", :bg => "default" },
  :starred => { :fg => "yellow", :bg => "default", :attrs => ["bold"] },
  :starred_patina => { :fg => "yellow", :bg => "green", :attrs => ["bold"] },
  :alternate_starred_patina => { :fg => "yellow", :bg => "blue", :attrs => ["bold"] },
  :snippet => { :fg => "cyan", :bg => "default" },
  :option => { :fg => "white", :bg => "default" },
  :tagged => { :fg => "yellow", :bg => "default", :attrs => ["bold"] },
  :draft_notification => { :fg => "red", :bg => "default", :attrs => ["bold"] },
  :completion_character => { :fg => "white", :bg => "default", :attrs => ["bold"] },
  :horizontal_selector_selected => { :fg => "yellow", :bg => "default", :attrs => ["bold"] },
  :horizontal_selector_unselected => { :fg => "cyan", :bg => "default" },
  :search_highlight => { :fg => "black", :bg => "yellow", :attrs => ["bold"] }
}
@@instance =
nil

Class Method Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Colormap) initialize {|_self| ... }

Returns a new instance of Colormap

Yields:

  • (_self)

Yield Parameters:



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/sup/colormap.rb', line 52

def initialize
  raise "only one instance can be created" if @@instance
  @@instance = self
  @entries = {}
  @color_pairs = {[Curses::COLOR_WHITE, Curses::COLOR_BLACK] => 0}
  @users = []
  @next_id = 0
  yield self if block_given?
  @entries[highlight_sym(:none)] = highlight_for(Curses::COLOR_WHITE,
                                                 Curses::COLOR_BLACK,
                                                 []) + [nil]
end

Class Method Details

+ (Object) instance



203
# File 'lib/sup/colormap.rb', line 203

def self.instance; @@instance; end

+ (Object) method_missing(meth, *a)



204
205
206
207
# File 'lib/sup/colormap.rb', line 204

def self.method_missing meth, *a
  Colormap.new unless @@instance
  @@instance.send meth, *a
end

Instance Method Details

- (Object) add(sym, fg, bg, attr = nil, opts = {})

Raises:

  • (ArgumentError)


65
66
67
68
69
70
71
72
73
# File 'lib/sup/colormap.rb', line 65

def add sym, fg, bg, attr=nil, opts={}
  raise ArgumentError, "color for #{sym} already defined" if @entries.member? sym
  raise ArgumentError, "color '#{fg}' unknown" unless CURSES_COLORS.include? fg
  raise ArgumentError, "color '#{bg}' unknown" unless CURSES_COLORS.include? bg
  attrs = [attr].flatten.compact

  @entries[sym] = [fg, bg, attrs, nil]
  @entries[highlight_sym(sym)] = opts[:highlight] ? @entries[opts[:highlight]] : highlight_for(fg, bg, attrs) + [nil]
end

- (Object) color_for(sym, highlight = false)

Raises:

  • (ArgumentError)


114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/sup/colormap.rb', line 114

def color_for sym, highlight=false
  sym = highlight_sym(sym) if highlight
  return Curses::COLOR_BLACK if sym == :none
  raise ArgumentError, "undefined color #{sym}" unless @entries.member? sym

  ## if this color is cached, return it
  fg, bg, attrs, color = @entries[sym]
  return color if color

  if(cp = @color_pairs[[fg, bg]])
    ## nothing
  else ## need to get a new colorpair
    @next_id = (@next_id + 1) % NUM_COLORS
    @next_id += 1 if @next_id == 0 # 0 is always white on black
    id = @next_id
    Redwood::log "colormap: for color #{sym}, using id #{id} -> #{fg}, #{bg}"
    Curses.init_pair id, fg, bg or raise ArgumentError,
      "couldn't initialize curses color pair #{fg}, #{bg} (key #{id})"

    cp = @color_pairs[[fg, bg]] = Curses.color_pair(id)
    ## delete the old mapping, if it exists
    if @users[cp]
      @users[cp].each do |usym|
        Redwood::log "dropping color #{usym} (#{id})"
        @entries[usym][3] = nil
      end
      @users[cp] = []
    end
  end

  ## by now we have a color pair
  color = attrs.inject(cp) { |color, attr| color | attr }
  @entries[sym][3] = color # fill the cache
  (@users[cp] ||= []) << sym # record entry as a user of that color pair
  color
end

- (Object) highlight_for(fg, bg, attrs)



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/sup/colormap.rb', line 79

def highlight_for fg, bg, attrs
  hfg =
    case fg
    when Curses::COLOR_BLUE
      Curses::COLOR_WHITE
    when Curses::COLOR_YELLOW, Curses::COLOR_GREEN
      fg
    else
      Curses::COLOR_BLACK
    end

  hbg = 
    case bg
    when Curses::COLOR_CYAN
      Curses::COLOR_YELLOW
    when Curses::COLOR_YELLOW
      Curses::COLOR_BLUE
    else
      Curses::COLOR_CYAN
    end

  attrs =
    if fg == Curses::COLOR_WHITE && attrs.include?(Curses::A_BOLD)
      [Curses::A_BOLD]
    else
      case hfg
      when Curses::COLOR_BLACK
        []
      else
        [Curses::A_BOLD]
      end
    end
  [hfg, hbg, attrs]
end

- (Object) highlight_sym(sym)



75
76
77
# File 'lib/sup/colormap.rb', line 75

def highlight_sym sym
  "#{sym}_highlight".intern
end

- (Object) populate_colormap

Try to use the user defined colors, in case of an error fall back to the default ones.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/sup/colormap.rb', line 153

def populate_colormap
  user_colors = if File.exists? Redwood::COLOR_FN
    Redwood::log "loading user colors from #{Redwood::COLOR_FN}"
    Redwood::load_yaml_obj Redwood::COLOR_FN
  end

  error = nil
  Colormap::DEFAULT_COLORS.each_pair do |k, v|
    fg = Curses.const_get "COLOR_#{v[:fg].upcase}"
    bg = Curses.const_get "COLOR_#{v[:bg].upcase}"
    attrs = v[:attrs] ? v[:attrs].map { |a| Curses.const_get "A_#{a.upcase}" } : []

    if user_colors && (ucolor = user_colors[k])
      if(ufg = ucolor[:fg])
        begin
          fg = Curses.const_get "COLOR_#{ufg.upcase}"
        rescue NameError
          error ||= "Warning: there is no color named \"#{ufg}\", using fallback."
          Redwood::log "Warning: there is no color named \"#{ufg}\""
        end
      end

      if(ubg = ucolor[:bg])
        begin
          bg = Curses.const_get "COLOR_#{ubg.upcase}"
        rescue NameError
          error ||= "Warning: there is no color named \"#{ubg}\", using fallback."
          Redwood::log "Warning: there is no color named \"#{ubg}\""
        end
      end

      if(uattrs = ucolor[:attrs])
        attrs = [*uattrs].flatten.map do |a|
          begin
            Curses.const_get "A_#{a.upcase}"
          rescue NameError
            error ||= "Warning: there is no attribute named \"#{a}\", using fallback."
            Redwood::log "Warning: there is no attribute named \"#{a}\", using fallback."
          end
        end
      end
    end

    symbol = (k.to_s + "_color").to_sym
    add symbol, fg, bg, attrs
  end

  BufferManager.flash error if error
end