Class: TmthemeToDeftheme::Main

Inherits:
Object
  • Object
show all
Defined in:
lib/tmtheme-to-deftheme.rb

Constant Summary collapse

SCOPE_MAP =
YAML.load_file(File.join(File.dirname(__FILE__),'..','data','scopes-to-faces.yml'))
TM_SCOPES =
SCOPE_MAP.map(&:first)
EMACS_FACES =
SCOPE_MAP.map{|a| a[1..-1]}

Instance Method Summary collapse

Constructor Details

#initialize(theme_filename, options) ⇒ Main



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/tmtheme-to-deftheme.rb', line 14

def initialize theme_filename, options
  @theme_filename  = theme_filename
  @options         = options

  @plist           = Plist4r.open @theme_filename
  @author          = @plist["author"]
  @name            = @plist["name"]
  @theme_name      = "#{@plist["name"]}".downcase.tr ' _', '-'
  @long_theme_name = "#{@theme_name}-theme"

  if @options[:f]
    @deftheme_filename = "#{@long_theme_name}.el"
    unless @options[:s]
      $stderr.puts "Creating: #{@deftheme_filename}"
    end
    if File.exist? @deftheme_filename
      unless @options[:o]
        $stderr.puts "#{@deftheme_filename} already exists, use -o to force overwrite"
        exit 1
      end
    end
    File.open(@deftheme_filename, "w") {|f| f.puts parse}
  else
    puts parse
  end
end

Instance Method Details

#darktheme?Boolean



132
133
134
# File 'lib/tmtheme-to-deftheme.rb', line 132

def darktheme?
  !lighttheme?
end

#debug_out(message) ⇒ Object



41
42
43
# File 'lib/tmtheme-to-deftheme.rb', line 41

def debug_out message
  $stderr.puts message if @options[:debug]
end

#face_attrs(s) ⇒ Object



74
75
76
# File 'lib/tmtheme-to-deftheme.rb', line 74

def face_attrs s
  "#{make_attr s, "foreground"} #{make_attr s, "background"} #{italic_underline_bold s}"
end

#fix_rgba(hexcolor) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/tmtheme-to-deftheme.rb', line 96

def fix_rgba hexcolor
  if hexcolor.length == 9
    c = Color::RGB.from_html hexcolor[0,7]
    a = hexcolor[7,2].to_i(16).to_f
    p = (a / 255.0) * 100.0
    unless @base_bg.nil?
      c.mix_with(@base_bg, p).html
    else
      c.html
    end
  elsif hexcolor.length == 7 || hexcolor.length == 4
    hexcolor
  end
end

#isolate_palette(faces) ⇒ Object



92
93
94
# File 'lib/tmtheme-to-deftheme.rb', line 92

def isolate_palette faces
  [map_palette_key( faces, "foreground"), map_palette_key( faces, "background")]
end

#italic_underline_bold(s) ⇒ Object



68
69
70
71
72
# File 'lib/tmtheme-to-deftheme.rb', line 68

def italic_underline_bold s
  if s["fontStyle"]
    s["fontStyle"].split(" ").map{|i| ":#{i} t" }.join " "
  end
end

#lighttheme?Boolean



136
137
138
# File 'lib/tmtheme-to-deftheme.rb', line 136

def lighttheme?
  @base_bg.brightness > 0.45
end

#make_attr(s, k) ⇒ Object



63
64
65
66
# File 'lib/tmtheme-to-deftheme.rb', line 63

def make_attr s, k
  debug_out "Make attrs: #{s[:face]} : #{k} : #{s} : #{s[k]}"
  ":#{k} \"#{s[k]}\"" if s[k]
end

#make_rainbow_parensObject



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/tmtheme-to-deftheme.rb', line 140

def make_rainbow_parens
  samples = if lighttheme?
    @foreground_palette.sort_by{|c| c.brightness }.select{|c| c.brightness < 0.65 }
  else
    @foreground_palette.sort_by{|c| - c.brightness }.select{|c| c.brightness > 0.45 }
  end

  debug_out "- Palette sample -------------------------------"
  debug_out samples.map(&:html)
  debug_out "- <<<<<<<<<<<<<< -------------------------------"

  values = palette_average_values samples
  @average_foregroung_color = values[:color]
  @darkest_foregroung_color = values[:darkest]
  @brightest_foregroung_color = values[:brightest]
  rainbow_top = @average_foregroung_color.mix_with @darkest_foregroung_color, 30

  9.times.collect do |i|
    rainbow_top.adjust_brightness(i * 10).html
  end
end

#map_palette_key(faces, key) ⇒ Object



88
89
90
# File 'lib/tmtheme-to-deftheme.rb', line 88

def map_palette_key faces, key
  faces.map{|f| Color::RGB.from_html f[:settings][key] if f[:settings][key]}.compact
end

#map_scope(scope) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/tmtheme-to-deftheme.rb', line 45

def map_scope scope
  if scope.index ","
    names = scope.split(",").map(&:strip)
    debug_out names
    first_match = names.map{|n| TM_SCOPES.find_index n}.compact.first
  else
    debug_out scope
    first_match = TM_SCOPES.find_index scope
  end

  if first_match.nil?
    nil
  else
    debug_out "#{first_match} :: #{scope} : #{EMACS_FACES[first_match]}"
    EMACS_FACES[first_match]
  end
end

#map_scope_to_emacs_face(hash) ⇒ Object



78
79
80
81
82
83
84
85
86
# File 'lib/tmtheme-to-deftheme.rb', line 78

def map_scope_to_emacs_face hash
  emacs_face = map_scope hash["scope"]
  return nil if emacs_face.nil?
  settings = hash["settings"]
  emacs_face = [emacs_face] unless emacs_face.class == Array
  mapped_scope = emacs_face.map{|face| {face: face, settings: settings, scope: hash["scope"]}}
  debug_out mapped_scope
  mapped_scope
end

#palette_average_values(sample_palette) ⇒ Object

Note: Foreground palette



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/tmtheme-to-deftheme.rb', line 112

def palette_average_values sample_palette
  samples = sample_palette.map{|c|
    c = c.to_hsl
    {hue: c.hue, sat: c.saturation, lvl: c.brightness}
  }

  avg = {}
  avg[:hue] = samples.map{|s| s[:hue]}.reduce{|sum,c| sum + c} / samples.size
  avg[:sat] = samples.map{|s| s[:sat]}.reduce{|sum,c| sum + c} / samples.size
  avg[:lvl] = samples.map{|s| s[:lvl]}.reduce{|sum,c| sum + c} / samples.size

  {
    color: Color::HSL.new(avg[:hue], avg[:sat], avg[:lvl]).to_rgb,
    avg: avg,
    brightest: sample_palette.max_by(&:brightness),
    darkest: sample_palette.min_by(&:brightness),
    samples: samples
  }
end

#parseObject



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
202
203
# File 'lib/tmtheme-to-deftheme.rb', line 162

def parse
  debug_out "= Converting : #{@theme_filename} =============================="
  debug_out "- tmTheme scope settings --------------------"
  debug_out @plist["settings"].to_yaml

  @base_settings   = @plist["settings"].first["settings"]
  @base_bg_hex     = fix_rgba @base_settings["background"]
  @base_bg         = Color::RGB.from_html @base_bg_hex
  @base_fg_hex     = fix_rgba @base_settings["foreground"]
  @base_fg         = Color::RGB.from_html @base_fg_hex

  @emacs_faces     = @plist["settings"].collect{|s| map_scope_to_emacs_face(s) if s["scope"] }.flatten.compact

  if lighttheme?
    debug_out "- Converting : Light Theme ----------------"
  else
    debug_out "- Converting : Dark Theme ----------------"
  end

  # Debug faces
  debug_out "- Mapped faces ------------------------------"

  # Fix any RGBA colors in the tmTheme
  @emacs_faces.each do |f|
    debug_out f.to_yaml
    f[:settings]["foreground"] = fix_rgba f[:settings]["foreground"] if f[:settings]["foreground"]
    f[:settings]["background"] = fix_rgba f[:settings]["background"] if f[:settings]["background"]
    debug_out f.to_yaml
  end

  @foreground_palette, @background_palette = isolate_palette @emacs_faces
  @rainbow_parens = make_rainbow_parens + ["#FF0000"]

  if @emacs_faces.select{|f| f[:face] == "font-lock-comment-face"}
    comment_face = @emacs_faces.select{|f| f[:face] == "font-lock-comment-face"}.first
    if comment_face
      @emacs_faces << {face: "font-lock-comment-delimiter-face", settings: comment_face[:settings]}
    end
  end

  render
end

#renderObject



205
206
207
208
209
210
211
212
213
214
215
# File 'lib/tmtheme-to-deftheme.rb', line 205

def render
  Erubis::Eruby.new(
                    File.read(
                              File.join(
                                        File.dirname(__FILE__),
                                        '..',
                                        'templates',
                                        'deftheme.erb.el'
                                        )))
    .result binding
end