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,154 @@
1
+ # encoding: utf-8
2
+
3
+ module SublimeDSL
4
+ module Tools
5
+
6
+ ##
7
+ # A string that would like to be a Regexp.
8
+ # May contain back-references to another RegexpWannabe,
9
+ # stored as '§1', '§2', etc.
10
+
11
+ class RegexpWannabe
12
+
13
+ attr_reader :source
14
+ attr_reader :regexp # may be nil if error
15
+ attr_reader :backref
16
+ attr_reader :error
17
+ attr_reader :warnings
18
+
19
+ # FIXME: warnings ignored in JSON DSLs
20
+
21
+ # FIXME: 3 possible sources: PList, JSON, Ruby Regexp
22
+ # - when from PList, the current way of doing things seems ok
23
+ # - when from JSON, \t & \n should be converted to \\t and \\n
24
+ # and back to \t & \n on output (they don't use (?x))
25
+ # - when from Ruby, source should not be altered on input,
26
+ # but the output depends on JSON vs PList
27
+
28
+ def initialize(source, backref = nil)
29
+ # encode in utf-8, remove escaped newlines
30
+ @source = source.encode('utf-8').gsub(/(^|[^\\](\\\\)*+)\\\n/, '\1')
31
+ @backref = backref
32
+ @regexp = nil
33
+ @error = nil
34
+ @warnings = []
35
+ try_conversion
36
+ @error = message_only(@error) if @error
37
+ @source.gsub!("\t", " ") if extended?
38
+ end
39
+
40
+ # Returns the ruby syntax.
41
+ #
42
+ # If #source contains a '/', tries to return an r-form <tt>%r'...'</tt> or <tt>%r:...:</tt> or
43
+ # <tt>%r!...!</tt>. If it does not, or if the #source contains all 3 characters <tt>':!</tt>,
44
+ # return <tt>/.../</tt> if +rform+ is false (the default), or <tt>%r/.../</tt> if +rform+ is
45
+ # true. (The latter syntax avoids warnings when the regexp is the first argument to a method
46
+ # and parentheses are not used around arguments.)
47
+
48
+ def inspect(rform = false)
49
+ str = extended? ? source : source.gsub("\t", '\t').gsub("\n", '\n')
50
+ s = rform ? '%r' : ''
51
+ return "#{s}/#{str}/" unless str.include?('/')
52
+ %w(' : !).each { |c| return "%r#{c}#{str}#{c}" unless str.include?(c) }
53
+ # replace / with \/ unless already escaped
54
+ escaped = str.gsub( %r"(^|[^\\](\\\\)*+)(?=/)", '\1\\')
55
+ "#{s}/#{escaped}/"
56
+ end
57
+
58
+ # Returns the string syntax.
59
+ # * If +json+ == false, the string is suitable for PList.
60
+ # * If +json+ == true, the string is suitable for JSON output with String#inspect.
61
+
62
+ def to_s(for_json = false)
63
+ if regexp
64
+ # remove \/ escapes
65
+ str = regexp.source.gsub( %r"(^|[^\\](\\\\)*+)\\(?=/)", '\1')
66
+ str = str.gsub("\t", '\t').gsub("\n", '\n') unless extended?
67
+ if for_json
68
+ str.gsub!( %r"(^|[^\\](\\\\)*+)\\n", "\\1\n")
69
+ str.gsub!( %r"(^|[^\\](\\\\)*+)\\t", "\\1\t")
70
+ end
71
+ else
72
+ str = source
73
+ end
74
+ str.gsub(/§(?=[1-9])/, '\\')
75
+ end
76
+
77
+ # Returns an array of fixme comments.
78
+ def fixmes
79
+ comments = []
80
+ error and
81
+ comments << "# FIXME: (error) #{error}"
82
+ source =~ /#[@${]/ and
83
+ comments << "# FIXME: (error) '#$&' will be interpreted as interpolation: escape '#' as '\\#'"
84
+ comments.concat warnings.map { |w| "# FIXME: (warning) #{w}" }
85
+ comments
86
+ end
87
+
88
+ # Returns the fixme comments for this regexp.
89
+ # If no fixme, returns an empty string.
90
+
91
+ def fixme_comments(indent = ' ')
92
+ fixmes.map { |c| "#{indent}#{c}\n" }.join
93
+ end
94
+
95
+ private
96
+
97
+ def extended?
98
+ source =~ /\(\?[im]*x(:|[-im]*\))/
99
+ end
100
+
101
+ def try_conversion
102
+ @warnings = capture_warnings { @regexp = Regexp.new(source) }
103
+ @backref = nil unless source =~ /§[1-9]/
104
+ rescue RegexpError => ex
105
+ msg = ex.message
106
+ unless backref && msg =~ /^invalid backref|^invalid pattern in look-behind/
107
+ @error = msg
108
+ return
109
+ end
110
+
111
+ if backref.error
112
+ warnings << 'contains references to a Regexp with an error'
113
+ return
114
+ end
115
+
116
+ # replace \n with §n (but \\n remains \\n, while \\\n => \\§n, etc.)
117
+ source.gsub!(/((^|[^\\])(\\\\)*)\\(?=[1-9])/, '\1§')
118
+
119
+ unless backref.warnings.empty?
120
+ warnings << 'contains references to a Regexp with warning(s)'
121
+ return
122
+ end
123
+
124
+ begin
125
+ @warnings = capture_warnings { @regexp = Regexp.new(source) }
126
+ rescue RegexpError => ex
127
+ @error = ex.message
128
+ end
129
+ end
130
+
131
+ def capture_warnings
132
+ prev_verbose, $VERBOSE = $VERBOSE, 2
133
+ prev_stderr, $stderr = $stderr, StringIO.new('', 'wb:utf-8')
134
+ yield
135
+ msg = $stderr.string
136
+ msg.lines.grep(/ warning: /).map do |line|
137
+ line = line[/.*? warning: (.*)/, 1]
138
+ message_only(line)
139
+ end
140
+ ensure
141
+ $stderr = prev_stderr
142
+ $VERBOSE = prev_verbose
143
+ end
144
+
145
+ def message_only(msg)
146
+ line = msg.lines.first.strip
147
+ line =~ /(.*?):/ and line = $1.strip
148
+ line
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module SublimeDSL
3
+ module Tools
4
+
5
+ ##
6
+ # A mix-in redefining #inspect so that it does not depend on #to_s.
7
+
8
+ module StableInspect
9
+
10
+ # Method not calling #to_s, and producing the standard #inspect output.
11
+ def inspect
12
+ '#<' << self.class.name << ':0x' << '%x' % (object_id << 1) <<
13
+ instance_variables.map { |v| " #{v}=#{instance_variable_get(v).inspect}" }.join(',') <<
14
+ '>'
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,37 @@
1
+
2
+ module SublimeDSL
3
+ module Tools
4
+
5
+ ##
6
+ # A mix-in allowing to compare objects based on value rather than identity.
7
+ #
8
+ # It redefines #eql?, #hash and #== based on a #value_id method, and
9
+ # provides a default implementation for #value_id.
10
+
11
+ module ValueEquality
12
+
13
+ # Returns true if the class of +other+ is the same or a subclass of +self.class+,
14
+ # and #value_id are the same using "==".
15
+
16
+ def eql?(other)
17
+ other.is_a?(self.class) && other.value_id == self.value_id
18
+ end
19
+
20
+ alias == eql?
21
+
22
+ # Returns #hash for #value_id.
23
+
24
+ def hash
25
+ value_id.hash
26
+ end
27
+
28
+ # Default value identity: array of instance variable values.
29
+
30
+ def value_id
31
+ instance_variables.map { |v| instance_variable_get(v) }
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ module SublimeDSL
4
+ module Tools
5
+
6
+ ##
7
+ # Tools to process XML.
8
+
9
+ module XML
10
+
11
+ # Regexp matching forbidden control characters.
12
+ FORBIDDEN_CHARS_RE = /[\x00-\x08\x0b\x0c\x0e-\x1f]/
13
+
14
+ # Hash { 'forbidden character' => 'abbreviation' }.
15
+ FORBIDDEN_CHARS_MAP = {
16
+ "\x00" => 'NUL',
17
+ "\x01" => 'SOH',
18
+ "\x02" => 'STX',
19
+ "\x03" => 'ETX',
20
+ "\x04" => 'EOT',
21
+ "\x05" => 'ENQ',
22
+ "\x06" => 'ACK',
23
+ "\x07" => 'BEL',
24
+ "\x08" => 'BS',
25
+ # "\x09" => 'HT',
26
+ # "\x0a" => 'LF',
27
+ "\x0b" => 'VT',
28
+ "\x0c" => 'FF',
29
+ # "\x0d" => 'CR',
30
+ "\x0e" => 'SO',
31
+ "\x0f" => 'SI',
32
+ "\x10" => 'DLE',
33
+ "\x11" => 'DC1',
34
+ "\x12" => 'DC2',
35
+ "\x13" => 'DC3',
36
+ "\x14" => 'DC4',
37
+ "\x15" => 'NAK',
38
+ "\x16" => 'SYN',
39
+ "\x17" => 'ETB',
40
+ "\x18" => 'CAN',
41
+ "\x19" => 'EM',
42
+ "\x1a" => 'SUB',
43
+ "\x1b" => 'ESC',
44
+ "\x1c" => 'FS',
45
+ "\x1d" => 'GS',
46
+ "\x1e" => 'RS',
47
+ "\x1f" => 'US'
48
+ }
49
+
50
+ # Returns a Nokogiri::XML::Document.
51
+ # Raises an exception if the text contains control characters
52
+ # forbidden in an XML document.
53
+ def self.load(string_or_io)
54
+ text = string_or_io.respond_to?(:read) ? string_or_io.read : string_or_io
55
+ if text =~ FORBIDDEN_CHARS_RE
56
+ abbrev = FORBIDDEN_CHARS_MAP[$&]
57
+ raise Error, "illegal control character in XML: #{$&.inspect} (#{abbrev})"
58
+ end
59
+
60
+ Nokogiri.XML(text, &:noblanks) # I hate this API
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'tools/blank_slate'
4
+ require_relative 'tools/console'
5
+ require_relative 'tools/helpers'
6
+ require_relative 'tools/regexp_wannabe'
7
+ require_relative 'tools/stable_inspect.rb'
8
+ require_relative 'tools/value_equality.rb'
9
+ require_relative 'tools/xml'
10
+
11
+ module SublimeDSL
12
+
13
+ module Tools
14
+
15
+ # Zips the content of +dir+ into file +archive+.
16
+ def self.zip(dir, archive)
17
+ dir = dir + '/' unless dir.end_with?('/')
18
+ Zip::File.open(archive, Zip::File::CREATE) do |zipfile|
19
+ Dir["#{dir}**/*"].each { |f| zipfile.add(f.sub(dir, ''), f) }
20
+ end
21
+ end
22
+
23
+ # Returns the running OS: :Windows, :OSX or :Linux.
24
+ def self.os
25
+ @os ||=
26
+ case RbConfig::CONFIG['host_os']
27
+ when /mswin|mingw/
28
+ :Windows
29
+ when /darwin/
30
+ :OSX
31
+ else
32
+ :Linux
33
+ end
34
+ end
35
+
36
+ # Replacement for characters forbidden in Windows file names.
37
+ FORBIDDEN_CHARS_MAP = {
38
+ '<' => '˂', # \u02C2 - modifier letter left arrowhead
39
+ '>' => '˃', # \u02C3 - modifier letter right arrowhead
40
+ ':' => '˸', # \u02F8 - modifier letter raised colon
41
+ '"' => 'ʺ', # \u02BA - double prime
42
+ '/' => '∕', # \u2215 - division slash
43
+ '|' => '¦', # \u00A6 - broken bar
44
+ '?' => 'ʔ', # \u0294 - latin letter glottal stop
45
+ '*' => '✶', # \u2736 - six pointed black star
46
+ '\\' => 'ʅ' # \u0285 - latin small letter squat reversed esh
47
+ }
48
+
49
+ # Regexp matching characters forbidden in Windows file names.
50
+ FORBIDDEN_RE = /[#{FORBIDDEN_CHARS_MAP.keys.map { |s| '\\' << s }.join}]/
51
+
52
+ # Returns an OS-compatible file name for +text+.
53
+ #
54
+ # Maps forbidden characters in Windows file names to something
55
+ # visually close (even on OSX and Linux):
56
+ # <>:"/|?*\ => ˂˃˸ʺ∕¦ʔ✶ʅ
57
+ #--
58
+ # TODO: allow the user to control this (with a config file).
59
+
60
+ def self.filename(text)
61
+ text.gsub(FORBIDDEN_RE, FORBIDDEN_CHARS_MAP)
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,23 @@
1
+ require 'rbconfig'
2
+ require 'json'
3
+ require 'nokogiri'
4
+ require 'tmpdir'
5
+ require 'zip'
6
+
7
+ require_relative 'sublime_dsl/core_ext'
8
+ require_relative 'sublime_dsl/tools'
9
+ require_relative 'sublime_dsl/textmate'
10
+ require_relative 'sublime_dsl/sublime_text'
11
+ require_relative 'sublime_dsl/cli'
12
+
13
+ module SublimeDSL
14
+
15
+ VERSION = '0.1.1'
16
+
17
+ class Error < StandardError; end
18
+ class OptionError < Error; end
19
+ class DSLError < Error; end
20
+
21
+ Console = Tools::Console.new
22
+
23
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sublime_dsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Thierry Lambert
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubyzip
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
55
+ description: |
56
+ Sublime DSL allows generating Sublime Text configuration files
57
+ from a Ruby DSL, giving the power of Ruby to develop and maintain
58
+ themes, grammars, snippets, key bindings, etc.
59
+ email: thyresias@gmail.com
60
+ executables:
61
+ - subdsl
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - README.md
65
+ - SYNTAX.md
66
+ files:
67
+ - README.md
68
+ - Rakefile
69
+ - SYNTAX.md
70
+ - bin/subdsl
71
+ - lib/sublime_dsl.rb
72
+ - lib/sublime_dsl/cli.rb
73
+ - lib/sublime_dsl/cli/export.rb
74
+ - lib/sublime_dsl/cli/import.rb
75
+ - lib/sublime_dsl/core_ext.rb
76
+ - lib/sublime_dsl/core_ext/enumerable.rb
77
+ - lib/sublime_dsl/core_ext/string.rb
78
+ - lib/sublime_dsl/sublime_text.rb
79
+ - lib/sublime_dsl/sublime_text/command.rb
80
+ - lib/sublime_dsl/sublime_text/command_set.rb
81
+ - lib/sublime_dsl/sublime_text/keyboard.rb
82
+ - lib/sublime_dsl/sublime_text/keymap.rb
83
+ - lib/sublime_dsl/sublime_text/keymap/dsl_reader.rb
84
+ - lib/sublime_dsl/sublime_text/macro.rb
85
+ - lib/sublime_dsl/sublime_text/menu.rb
86
+ - lib/sublime_dsl/sublime_text/mouse.rb
87
+ - lib/sublime_dsl/sublime_text/mousemap.rb
88
+ - lib/sublime_dsl/sublime_text/package.rb
89
+ - lib/sublime_dsl/sublime_text/package/dsl_reader.rb
90
+ - lib/sublime_dsl/sublime_text/package/exporter.rb
91
+ - lib/sublime_dsl/sublime_text/package/importer.rb
92
+ - lib/sublime_dsl/sublime_text/package/reader.rb
93
+ - lib/sublime_dsl/sublime_text/package/writer.rb
94
+ - lib/sublime_dsl/sublime_text/setting_set.rb
95
+ - lib/sublime_dsl/textmate.rb
96
+ - lib/sublime_dsl/textmate/custom_base_name.rb
97
+ - lib/sublime_dsl/textmate/grammar.rb
98
+ - lib/sublime_dsl/textmate/grammar/dsl_reader.rb
99
+ - lib/sublime_dsl/textmate/grammar/dsl_writer.rb
100
+ - lib/sublime_dsl/textmate/grammar/plist_reader.rb
101
+ - lib/sublime_dsl/textmate/grammar/plist_writer.rb
102
+ - lib/sublime_dsl/textmate/plist.rb
103
+ - lib/sublime_dsl/textmate/preference.rb
104
+ - lib/sublime_dsl/textmate/snippet.rb
105
+ - lib/sublime_dsl/textmate/theme.rb
106
+ - lib/sublime_dsl/textmate/theme/dsl_reader.rb
107
+ - lib/sublime_dsl/textmate/theme/item.rb
108
+ - lib/sublime_dsl/textmate/theme/plist_writer.rb
109
+ - lib/sublime_dsl/tools.rb
110
+ - lib/sublime_dsl/tools/blank_slate.rb
111
+ - lib/sublime_dsl/tools/console.rb
112
+ - lib/sublime_dsl/tools/helpers.rb
113
+ - lib/sublime_dsl/tools/regexp_wannabe.rb
114
+ - lib/sublime_dsl/tools/stable_inspect.rb
115
+ - lib/sublime_dsl/tools/value_equality.rb
116
+ - lib/sublime_dsl/tools/xml.rb
117
+ homepage: https://github.com/thyresias/sublime_dsl
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options:
123
+ - "--title"
124
+ - Sublime DSL
125
+ - "--main"
126
+ - README.md
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.4.1
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: A DSL to specify Sublime Text packages.
145
+ test_files: []