sublime_dsl 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +136 -0
  3. data/Rakefile +248 -0
  4. data/SYNTAX.md +927 -0
  5. data/bin/subdsl +4 -0
  6. data/lib/sublime_dsl/cli/export.rb +134 -0
  7. data/lib/sublime_dsl/cli/import.rb +143 -0
  8. data/lib/sublime_dsl/cli.rb +125 -0
  9. data/lib/sublime_dsl/core_ext/enumerable.rb +24 -0
  10. data/lib/sublime_dsl/core_ext/string.rb +129 -0
  11. data/lib/sublime_dsl/core_ext.rb +4 -0
  12. data/lib/sublime_dsl/sublime_text/command.rb +157 -0
  13. data/lib/sublime_dsl/sublime_text/command_set.rb +112 -0
  14. data/lib/sublime_dsl/sublime_text/keyboard.rb +659 -0
  15. data/lib/sublime_dsl/sublime_text/keymap/dsl_reader.rb +194 -0
  16. data/lib/sublime_dsl/sublime_text/keymap.rb +385 -0
  17. data/lib/sublime_dsl/sublime_text/macro.rb +91 -0
  18. data/lib/sublime_dsl/sublime_text/menu.rb +237 -0
  19. data/lib/sublime_dsl/sublime_text/mouse.rb +149 -0
  20. data/lib/sublime_dsl/sublime_text/mousemap.rb +185 -0
  21. data/lib/sublime_dsl/sublime_text/package/dsl_reader.rb +91 -0
  22. data/lib/sublime_dsl/sublime_text/package/exporter.rb +138 -0
  23. data/lib/sublime_dsl/sublime_text/package/importer.rb +127 -0
  24. data/lib/sublime_dsl/sublime_text/package/reader.rb +102 -0
  25. data/lib/sublime_dsl/sublime_text/package/writer.rb +112 -0
  26. data/lib/sublime_dsl/sublime_text/package.rb +96 -0
  27. data/lib/sublime_dsl/sublime_text/setting_set.rb +123 -0
  28. data/lib/sublime_dsl/sublime_text.rb +48 -0
  29. data/lib/sublime_dsl/textmate/custom_base_name.rb +45 -0
  30. data/lib/sublime_dsl/textmate/grammar/dsl_reader.rb +383 -0
  31. data/lib/sublime_dsl/textmate/grammar/dsl_writer.rb +178 -0
  32. data/lib/sublime_dsl/textmate/grammar/plist_reader.rb +163 -0
  33. data/lib/sublime_dsl/textmate/grammar/plist_writer.rb +153 -0
  34. data/lib/sublime_dsl/textmate/grammar.rb +252 -0
  35. data/lib/sublime_dsl/textmate/plist.rb +141 -0
  36. data/lib/sublime_dsl/textmate/preference.rb +301 -0
  37. data/lib/sublime_dsl/textmate/snippet.rb +437 -0
  38. data/lib/sublime_dsl/textmate/theme/dsl_reader.rb +87 -0
  39. data/lib/sublime_dsl/textmate/theme/item.rb +74 -0
  40. data/lib/sublime_dsl/textmate/theme/plist_writer.rb +53 -0
  41. data/lib/sublime_dsl/textmate/theme.rb +364 -0
  42. data/lib/sublime_dsl/textmate.rb +9 -0
  43. data/lib/sublime_dsl/tools/blank_slate.rb +49 -0
  44. data/lib/sublime_dsl/tools/console.rb +74 -0
  45. data/lib/sublime_dsl/tools/helpers.rb +152 -0
  46. data/lib/sublime_dsl/tools/regexp_wannabe.rb +154 -0
  47. data/lib/sublime_dsl/tools/stable_inspect.rb +20 -0
  48. data/lib/sublime_dsl/tools/value_equality.rb +37 -0
  49. data/lib/sublime_dsl/tools/xml.rb +66 -0
  50. data/lib/sublime_dsl/tools.rb +66 -0
  51. data/lib/sublime_dsl.rb +23 -0
  52. metadata +145 -0
@@ -0,0 +1,364 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'theme/item'
4
+ require_relative 'theme/dsl_reader'
5
+ require_relative 'theme/plist_writer'
6
+
7
+ module SublimeDSL
8
+ module TextMate
9
+
10
+ class Theme
11
+
12
+ # Create from a PList file.
13
+ def self.import(file)
14
+ p = PList.import(file)
15
+ t = new(p.delete('name'))
16
+ t.basename = File.basename(file, File.extname(file))
17
+ t.author = p.delete('author')
18
+ t.uuid = p.delete('uuid')
19
+ t.comment = p.delete('comment')
20
+ t.license = p.delete('license')
21
+ p.delete('settings').each do |h|
22
+ n = h['name']
23
+ s = h['scope'] && h['scope'].strip
24
+ if n || s
25
+ e = Item.new(n, s)
26
+ h['settings'].each_pair do |prop, value|
27
+ next if value.empty?
28
+ e.send "#{prop.snake_case}=", value
29
+ end
30
+ t.add_item e
31
+ else
32
+ h['settings'].each_pair do |prop, color|
33
+ key = prop.snake_case #.to_sym
34
+ color.upcase! if color =~ /^#/
35
+ t.base_colors[key] = color
36
+ end
37
+ end
38
+ end
39
+ p.empty? or raise Error, "unknown theme keys: #{p.inspect}"
40
+ t
41
+ end
42
+
43
+ # Returns the content of this file after __END__
44
+ # (DATA is not available for required files).
45
+
46
+ def self.color_data # :nodoc:
47
+ data = ''
48
+ File.open(__FILE__) do |f|
49
+ in_data = false
50
+ f.each_line do |line|
51
+ if line =~ /^__END__/
52
+ in_data = true
53
+ elsif in_data
54
+ data << line
55
+ end
56
+ end
57
+ end
58
+ data
59
+ end
60
+
61
+ # Hash { '#xxxxxx' => color_name }, read from the
62
+ # DATA section of this file.
63
+
64
+ COLOR_NAMES_HASH = {}
65
+
66
+ color_data.each_line do |line|
67
+ line.strip!
68
+ next if line.empty? || line.start_with?('=')
69
+ name, value = line.split(/\s+/)
70
+ COLOR_NAMES_HASH["##{value}"] = name.snake_case
71
+ end
72
+
73
+ include CustomBaseName
74
+
75
+ attr_accessor :name, :author, :uuid, :comment, :license
76
+
77
+ # base color hash:
78
+ # background
79
+ # caret
80
+ # foreground
81
+ # invisibles
82
+ # line_highlight
83
+ # selection
84
+ # selection_border
85
+ # inactive_selection
86
+ #
87
+ # Monokai* also have:
88
+ # inactive_selection
89
+ # inactive_selection_foreground
90
+ # find_highlight
91
+ # find_highlight_foreground
92
+ # active_guide
93
+ # brackets_foreground
94
+ # brackets_options
95
+ # bracket_contents_foreground
96
+ # bracket_contents_options
97
+
98
+ attr_reader :base_colors
99
+
100
+ # array of defined items
101
+ attr_reader :items
102
+
103
+ def initialize(name)
104
+ @name = name
105
+ @author = nil
106
+ @uuid = nil
107
+ @comment = nil
108
+ @license = nil
109
+ @base_colors = {}
110
+ @items = []
111
+ end
112
+
113
+ def add_item(e)
114
+ warn "unnamed item in theme #{name.inspect}" unless e.name
115
+ warn "empty scope for item '#{e.name}' in theme #{name.inspect}" unless e.scope
116
+ e.name && items.any? { |el| el.name == e.name } and
117
+ warn "duplicate item name '#{e.name}' in theme #{name.inspect}"
118
+ items << e
119
+ end
120
+
121
+ def to_dsl
122
+ out = StringIO.new('', 'wb:utf-8')
123
+
124
+ args = name.to_source
125
+ args << dsl_file_arg
126
+
127
+ out.puts comment.strip.lines.map { |l| "# #{l}" }.join << "\n\n" if comment
128
+ out.puts "theme #{args} do"
129
+ out.puts
130
+ out.puts " author '#{author}'" if author
131
+ out.puts " uuid '#{uuid}'" if uuid
132
+ if license
133
+ out.puts
134
+ out.puts " license <<-TXT"
135
+ license.lines.each { |l| out.puts l.strip.empty? ? '' : l.strip.wrap.indent(4) }
136
+ out.puts " TXT"
137
+ end
138
+
139
+ out.puts
140
+ max = colors_hash.values.map(&:length).max
141
+ colors_hash.each_pair do |color, name|
142
+ out.puts " %*1$2$s = '%3$s'" % [-max, name, color]
143
+ end
144
+
145
+ out.puts
146
+ out.puts " base_colors("
147
+ base_colors.each_pair do |k,v|
148
+ out.puts " #{k}: #{colors_hash[v]},"
149
+ end
150
+ out.puts " )"
151
+
152
+ out.puts
153
+ names_hash = items.group_by(&:name)
154
+ items.each do |e|
155
+ out.puts ' # FIXME: duplicate name:' if e.name && names_hash[e.name].length > 1
156
+ out.puts e.to_dsl(colors_hash).indent(2)
157
+ end
158
+
159
+ out.puts "\nend"
160
+
161
+ out.string
162
+ end
163
+
164
+ def write(dir)
165
+ file = "#{dir}/#{basename}.tmTheme.rb"
166
+ File.open(file, 'wb:utf-8') do |f|
167
+ f.puts '# encoding: utf-8'
168
+ f.puts "\n" << to_dsl
169
+ end
170
+ end
171
+
172
+ def export(dir)
173
+ file = "#{dir}/#{basename}.tmTheme"
174
+ PListWriter.new(self).export(file)
175
+ end
176
+
177
+ # A Hash { <color value> => <color name> }.
178
+ def colors_hash
179
+ @colors_hash ||= begin
180
+ colors = base_colors.values + items.flat_map(&:colors)
181
+ colors.uniq!
182
+ h = {}
183
+ colors.each_with_index { |c, i| h[c] = COLOR_NAMES_HASH[c] || "color#{i}" }
184
+ h
185
+ end
186
+ end
187
+
188
+ end
189
+
190
+ end
191
+ end
192
+
193
+ __END__
194
+
195
+ = Red
196
+
197
+ IndianRed CD5C5C
198
+ LightCoral F08080
199
+ Salmon FA8072
200
+ DarkSalmon E9967A
201
+ LightSalmon FFA07A
202
+ Crimson DC143C
203
+ Red FF0000
204
+ FireBrick B22222
205
+ DarkRed 8B0000
206
+
207
+ = Pink
208
+
209
+ Pink FFC0CB
210
+ LightPink FFB6C1
211
+ HotPink FF69B4
212
+ DeepPink FF1493
213
+ MediumVioletRed C71585
214
+ PaleVioletRed DB7093
215
+
216
+ = Orange
217
+
218
+ LightSalmon FFA07A
219
+ Coral FF7F50
220
+ Tomato FF6347
221
+ OrangeRed FF4500
222
+ DarkOrange FF8C00
223
+ Orange FFA500
224
+
225
+ = Yellow
226
+
227
+ Gold FFD700
228
+ Yellow FFFF00
229
+ LightYellow FFFFE0
230
+ LemonChiffon FFFACD
231
+ LightGoldenrodYellow FAFAD2
232
+ PapayaWhip FFEFD5
233
+ Moccasin FFE4B5
234
+ PeachPuff FFDAB9
235
+ PaleGoldenrod EEE8AA
236
+ Khaki F0E68C
237
+ DarkKhaki BDB76B
238
+
239
+ = Purple
240
+
241
+ Lavender E6E6FA
242
+ Thistle D8BFD8
243
+ Plum DDA0DD
244
+ Violet EE82EE
245
+ Orchid DA70D6
246
+ Fuchsia FF00FF
247
+ Magenta FF00FF
248
+ MediumOrchid BA55D3
249
+ MediumPurple 9370DB
250
+ BlueViolet 8A2BE2
251
+ DarkViolet 9400D3
252
+ DarkOrchid 9932CC
253
+ DarkMagenta 8B008B
254
+ Purple 800080
255
+ Indigo 4B0082
256
+ SlateBlue 6A5ACD
257
+ DarkSlateBlue 483D8B
258
+
259
+ = Green
260
+
261
+ GreenYellow ADFF2F
262
+ Chartreuse 7FFF00
263
+ LawnGreen 7CFC00
264
+ Lime 00FF00
265
+ LimeGreen 32CD32
266
+ PaleGreen 98FB98
267
+ LightGreen 90EE90
268
+ MediumSpringGreen 00FA9A
269
+ SpringGreen 00FF7F
270
+ MediumSeaGreen 3CB371
271
+ SeaGreen 2E8B57
272
+ ForestGreen 228B22
273
+ Green 008000
274
+ DarkGreen 006400
275
+ YellowGreen 9ACD32
276
+ OliveDrab 6B8E23
277
+ Olive 808000
278
+ DarkOliveGreen 556B2F
279
+ MediumAquamarine 66CDAA
280
+ DarkSeaGreen 8FBC8F
281
+ LightSeaGreen 20B2AA
282
+ DarkCyan 008B8B
283
+ Teal 008080
284
+
285
+ = Blue
286
+
287
+ Aqua 00FFFF
288
+ Cyan 00FFFF
289
+ LightCyan E0FFFF
290
+ PaleTurquoise AFEEEE
291
+ Aquamarine 7FFFD4
292
+ Turquoise 40E0D0
293
+ MediumTurquoise 48D1CC
294
+ DarkTurquoise 00CED1
295
+ CadetBlue 5F9EA0
296
+ SteelBlue 4682B4
297
+ LightSteelBlue B0C4DE
298
+ PowderBlue B0E0E6
299
+ LightBlue ADD8E6
300
+ SkyBlue 87CEEB
301
+ LightSkyBlue 87CEFA
302
+ DeepSkyBlue 00BFFF
303
+ DodgerBlue 1E90FF
304
+ CornflowerBlue 6495ED
305
+ MediumSlateBlue 7B68EE
306
+ RoyalBlue 4169E1
307
+ Blue 0000FF
308
+ MediumBlue 0000CD
309
+ DarkBlue 00008B
310
+ Navy 000080
311
+ MidnightBlue 191970
312
+
313
+ = Brown
314
+
315
+ Cornsilk FFF8DC
316
+ BlanchedAlmond FFEBCD
317
+ Bisque FFE4C4
318
+ NavajoWhite FFDEAD
319
+ Wheat F5DEB3
320
+ BurlyWood DEB887
321
+ Tan D2B48C
322
+ RosyBrown BC8F8F
323
+ SandyBrown F4A460
324
+ Goldenrod DAA520
325
+ DarkGoldenrod B8860B
326
+ Peru CD853F
327
+ Chocolate D2691E
328
+ SaddleBrown 8B4513
329
+ Sienna A0522D
330
+ Brown A52A2A
331
+ Maroon 800000
332
+
333
+ = White
334
+
335
+ White FFFFFF
336
+ Snow FFFAFA
337
+ Honeydew F0FFF0
338
+ MintCream F5FFFA
339
+ Azure F0FFFF
340
+ AliceBlue F0F8FF
341
+ GhostWhite F8F8FF
342
+ WhiteSmoke F5F5F5
343
+ Seashell FFF5EE
344
+ Beige F5F5DC
345
+ OldLace FDF5E6
346
+ FloralWhite FFFAF0
347
+ Ivory FFFFF0
348
+ AntiqueWhite FAEBD7
349
+ Linen FAF0E6
350
+ LavenderBlush FFF0F5
351
+ MistyRose FFE4E1
352
+
353
+ = Grey
354
+
355
+ Gainsboro DCDCDC
356
+ LightGrey D3D3D3
357
+ Silver C0C0C0
358
+ DarkGray A9A9A9
359
+ Gray 808080
360
+ DimGray 696969
361
+ LightSlateGray 778899
362
+ SlateGray 708090
363
+ DarkSlateGray 2F4F4F
364
+ Black 000000
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'textmate/plist'
4
+ require_relative 'textmate/custom_base_name'
5
+
6
+ require_relative 'textmate/grammar'
7
+ require_relative 'textmate/snippet'
8
+ require_relative 'textmate/preference'
9
+ require_relative 'textmate/theme'
@@ -0,0 +1,49 @@
1
+
2
+ module SublimeDSL
3
+ module Tools
4
+
5
+ ##
6
+ # A class with a minimal set of methods, used for DSL readers
7
+ # that heavily rely on #method_missing.
8
+
9
+ class BlankSlate < Object
10
+
11
+ # Methods kept:
12
+ # - public/protected from BasicObject, except operators
13
+ # - private from BasicObject
14
+ # - a few Object/Kernel methods
15
+
16
+ KEPT_METHODS = %w(
17
+ __id__
18
+ __send__
19
+ equal?
20
+ instance_eval
21
+ instance_exec
22
+
23
+ initialize
24
+ method_missing
25
+ singleton_method_added
26
+ singleton_method_removed
27
+ singleton_method_undefined
28
+
29
+ __callee__
30
+ __method__
31
+ caller
32
+ define_singleton_method
33
+ method
34
+ object_id
35
+ p
36
+ puts
37
+ raise
38
+ singleton_methods
39
+ warn
40
+ ).map(&:to_sym)
41
+
42
+ (instance_methods + private_instance_methods - KEPT_METHODS).each do |m|
43
+ undef_method m
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,74 @@
1
+
2
+ module SublimeDSL
3
+ module Tools
4
+
5
+ ##
6
+ # Tools for console interaction.
7
+
8
+ class Console
9
+
10
+ attr_reader :verbosity
11
+ attr_accessor :set_ruby_verbosity
12
+ attr_reader :in_progress
13
+
14
+ def initialize
15
+ @verbosity = 1
16
+ @set_ruby_verbosity = true
17
+ @in_progress = false
18
+ end
19
+
20
+ def error(text)
21
+ end_progress
22
+ $stderr.puts text
23
+ end
24
+
25
+ def verbosity=(value)
26
+ if set_ruby_verbosity
27
+ case value
28
+ when 0 then $VERBOSE = nil
29
+ when 1 then $VERBOSE = false
30
+ when 2 then $VERBOSE = true
31
+ end
32
+ end
33
+ @verbosity = value
34
+ end
35
+
36
+ def info(text, force = false)
37
+ return unless $stdout.tty? && (verbosity > 0 || force)
38
+ end_progress
39
+ puts text
40
+ end
41
+
42
+ def width
43
+ (ENV['COLUMNS'] || 80).to_i
44
+ end
45
+
46
+ def progress(index, count, file, force = false)
47
+ return unless $stdout.tty? && (verbosity == 2 || force)
48
+ @in_progress = true
49
+ c = count.to_s
50
+ prefix = "file %#{c.length}d/#{c}: " % index
51
+ line = "#{prefix}#{file}"
52
+ padding = width - line.length - 1
53
+ if padding < 0
54
+ file = file[(-padding) .. -1]
55
+ file[0..2] = "..."
56
+ line = "#{prefix}#{file}"
57
+ else
58
+ line << ' ' * padding
59
+ end
60
+ print "#{line}\r"
61
+ $stdout.flush
62
+ end
63
+
64
+ private
65
+
66
+ def end_progress
67
+ puts() if in_progress
68
+ @in_progress = false
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,152 @@
1
+
2
+ module SublimeDSL
3
+ module Tools
4
+
5
+ ##
6
+ # Helper methods to include in DSL blocks as needed.
7
+
8
+ module Helpers
9
+
10
+ # Return an optimized regexp string matching a word in +words+. Example:
11
+ # include SublimeDSL::Tools::Helpers
12
+ # list = %w(abs addr addrlong airy allcomb allperm anyalnum anyalpha anycntrl)
13
+ # optimized_re(list)
14
+ # => 'a(bs|ddr(long)?|iry|ll(comb|perm)|ny(al(num|pha)|cntrl))'
15
+
16
+ def optimized_re(words)
17
+ root = Node.new('')
18
+ root.add_children words
19
+ root.reduce!
20
+ root.to_re
21
+ end
22
+
23
+ module_function :optimized_re
24
+
25
+ end
26
+
27
+ ##
28
+ # A node in the optimization of a Regexp matching a list of keywords.
29
+
30
+ class Node
31
+
32
+ # The start string.
33
+ attr_reader :start
34
+
35
+ # The child nodes.
36
+ attr_reader :children
37
+
38
+ # Creates a new node for the +start+ string, with an empty list of children.
39
+ def initialize(start)
40
+ @start = start
41
+ @children = []
42
+ end
43
+
44
+ # The node representing the end of a string: an empty string with no child.
45
+ NULL = self.new('')
46
+
47
+ # Adds +words+ to the children of the current node:
48
+ # the children of the current node are the unique initial letters of words,
49
+ # and the following letters are recurisvely added as grandchildren:
50
+ # x = Node.new('')
51
+ # x.add_children %w(a abc abd abde)
52
+ # => tree:
53
+ # ""
54
+ # "a"
55
+ # ""
56
+ # "b"
57
+ # "c"
58
+ # ""
59
+ # "d"
60
+ # ""
61
+ # "e"
62
+ # ""
63
+
64
+ def add_children(words)
65
+ words.group_by { |w| w[0] }.each_pair do |letter, list|
66
+ if letter.nil?
67
+ self.children << Node::NULL
68
+ else
69
+ n = Node.new(letter.dup)
70
+ self.children << n
71
+ n.add_children list.map { |w| w[1..-1] }
72
+ end
73
+ end
74
+ end
75
+
76
+ # Reduce the current node:
77
+ # - first reduce all children
78
+ # - then if there is only one +child+ left:
79
+ # - append the child#start value to self#start
80
+ # - replace the children of +self+ by the children of +child+
81
+ # Example:
82
+ # x = Node.new('')
83
+ # x.add_children %w(abs addr addrlong airy allcomb allperm anyalnum anyalpha anycntrl)
84
+ # x.reduce!
85
+ # => tree:
86
+ # "a"
87
+ # "bs"
88
+ # "ddr"
89
+ # ""
90
+ # "long"
91
+ # "iry"
92
+ # "ll"
93
+ # "comb"
94
+ # "perm"
95
+ # "ny"
96
+ # "al"
97
+ # "num"
98
+ # "pha"
99
+ # "cntrl"
100
+
101
+ def reduce!
102
+ children.each(&:reduce!)
103
+ if children.length == 1
104
+ child = children.first
105
+ @start << child.start
106
+ @children = child.children
107
+ end
108
+ end
109
+
110
+ # Converts the current node to a regular expression string:
111
+ # x = Node.new('')
112
+ # x.add_children %w(abs addr addrlong airy allcomb allperm anyalnum anyalpha anycntrl)
113
+ # x.reduce!
114
+ # x.to_re
115
+ # => 'a(bs|ddr(long)?|iry|ll(comb|perm)|ny(al(num|pha)|cntrl))'
116
+
117
+ def to_re
118
+ t, list = children.partition { |c| c == NULL }
119
+ t = t.first
120
+ start + (
121
+ case list.length
122
+ when 0
123
+ ''
124
+ when 1
125
+ r = list.first.to_re
126
+ r.length == 1 ? r : '(' + r + ')'
127
+ else
128
+ r = list.map(&:to_re)
129
+ if r.all? { |s| s.length == 1 }
130
+ '[' + r.join + ']'
131
+ else
132
+ '(' + r.join('|') + ')'
133
+ end
134
+ end
135
+ ) + (
136
+ ( t ? '?' : '' )
137
+ )
138
+ end
139
+
140
+ # The display tree for the current node.
141
+
142
+ def display_tree(indent = '')
143
+ return indent + start.inspect if children.empty?
144
+ [ indent + start.inspect,
145
+ children.map { |c| c.display_tree(indent+' ') },
146
+ ].join("\n")
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+ end