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.
- checksums.yaml +7 -0
- data/README.md +136 -0
- data/Rakefile +248 -0
- data/SYNTAX.md +927 -0
- data/bin/subdsl +4 -0
- data/lib/sublime_dsl/cli/export.rb +134 -0
- data/lib/sublime_dsl/cli/import.rb +143 -0
- data/lib/sublime_dsl/cli.rb +125 -0
- data/lib/sublime_dsl/core_ext/enumerable.rb +24 -0
- data/lib/sublime_dsl/core_ext/string.rb +129 -0
- data/lib/sublime_dsl/core_ext.rb +4 -0
- data/lib/sublime_dsl/sublime_text/command.rb +157 -0
- data/lib/sublime_dsl/sublime_text/command_set.rb +112 -0
- data/lib/sublime_dsl/sublime_text/keyboard.rb +659 -0
- data/lib/sublime_dsl/sublime_text/keymap/dsl_reader.rb +194 -0
- data/lib/sublime_dsl/sublime_text/keymap.rb +385 -0
- data/lib/sublime_dsl/sublime_text/macro.rb +91 -0
- data/lib/sublime_dsl/sublime_text/menu.rb +237 -0
- data/lib/sublime_dsl/sublime_text/mouse.rb +149 -0
- data/lib/sublime_dsl/sublime_text/mousemap.rb +185 -0
- data/lib/sublime_dsl/sublime_text/package/dsl_reader.rb +91 -0
- data/lib/sublime_dsl/sublime_text/package/exporter.rb +138 -0
- data/lib/sublime_dsl/sublime_text/package/importer.rb +127 -0
- data/lib/sublime_dsl/sublime_text/package/reader.rb +102 -0
- data/lib/sublime_dsl/sublime_text/package/writer.rb +112 -0
- data/lib/sublime_dsl/sublime_text/package.rb +96 -0
- data/lib/sublime_dsl/sublime_text/setting_set.rb +123 -0
- data/lib/sublime_dsl/sublime_text.rb +48 -0
- data/lib/sublime_dsl/textmate/custom_base_name.rb +45 -0
- data/lib/sublime_dsl/textmate/grammar/dsl_reader.rb +383 -0
- data/lib/sublime_dsl/textmate/grammar/dsl_writer.rb +178 -0
- data/lib/sublime_dsl/textmate/grammar/plist_reader.rb +163 -0
- data/lib/sublime_dsl/textmate/grammar/plist_writer.rb +153 -0
- data/lib/sublime_dsl/textmate/grammar.rb +252 -0
- data/lib/sublime_dsl/textmate/plist.rb +141 -0
- data/lib/sublime_dsl/textmate/preference.rb +301 -0
- data/lib/sublime_dsl/textmate/snippet.rb +437 -0
- data/lib/sublime_dsl/textmate/theme/dsl_reader.rb +87 -0
- data/lib/sublime_dsl/textmate/theme/item.rb +74 -0
- data/lib/sublime_dsl/textmate/theme/plist_writer.rb +53 -0
- data/lib/sublime_dsl/textmate/theme.rb +364 -0
- data/lib/sublime_dsl/textmate.rb +9 -0
- data/lib/sublime_dsl/tools/blank_slate.rb +49 -0
- data/lib/sublime_dsl/tools/console.rb +74 -0
- data/lib/sublime_dsl/tools/helpers.rb +152 -0
- data/lib/sublime_dsl/tools/regexp_wannabe.rb +154 -0
- data/lib/sublime_dsl/tools/stable_inspect.rb +20 -0
- data/lib/sublime_dsl/tools/value_equality.rb +37 -0
- data/lib/sublime_dsl/tools/xml.rb +66 -0
- data/lib/sublime_dsl/tools.rb +66 -0
- data/lib/sublime_dsl.rb +23 -0
- metadata +145 -0
data/SYNTAX.md
ADDED
@@ -0,0 +1,927 @@
|
|
1
|
+
|
2
|
+
This preliminary documentation supposes you are familiar with the configuration files
|
3
|
+
of TextMate (grammars, preferences, snippets and themes) and Sublime Text (commands,
|
4
|
+
keymaps, mousemaps, menus, settings).
|
5
|
+
|
6
|
+
## General Design
|
7
|
+
|
8
|
+
### Import: Converting to DSL
|
9
|
+
|
10
|
+
When importing a ST package, some files are grouped into one DSL file:
|
11
|
+
|
12
|
+
- all macros (*.sublime-macro) are grouped into macros.rb
|
13
|
+
- all snippets (*.sublime-snippet, *.tmSnippet) are grouped into snippets.rb
|
14
|
+
- all commands (*.sublime-commands) are grouped into commands.rb
|
15
|
+
- all preferences (*.tmPreferences) are grouped into preferences.rb
|
16
|
+
- all settings (*.sublime-settings) are grouped into settings.rb
|
17
|
+
|
18
|
+
Other files generate one DSL file:
|
19
|
+
|
20
|
+
- *.tmLanguage => *.tmLanguage.rb
|
21
|
+
- *.sublime-menu => *.menu.rb
|
22
|
+
- *.sublime-keymap => *.keymap.rb
|
23
|
+
- *.sublime-mousemap => *.mousemap.rb
|
24
|
+
|
25
|
+
Finally, files with an extension not listed above (e.g., *.py) are copied "as is".
|
26
|
+
In particular, there is no DSL (yet?) for *.sublime-build and *.sublime-completions.
|
27
|
+
|
28
|
+
### Export: Converting from DSL
|
29
|
+
|
30
|
+
The export processes all *.rb files located in the DSL directory, and copies
|
31
|
+
other files "as is". Therefore, the organization of DSL files is free: a whole
|
32
|
+
package can be specified into one source file, or into several source files.
|
33
|
+
|
34
|
+
## Grammars
|
35
|
+
|
36
|
+
Grammars are defined with the `language` method:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
language 'Ruby' => 'source.ruby' do
|
40
|
+
# definitions
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
The exported file by will be named 'Ruby.tmLanguage', unless a :file option is given:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
language 'Ruby' => 'source.ruby', :file => 'MyRuby' do
|
48
|
+
# definitions
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
Inside the `language` block, the properties correspond to method calls with the
|
53
|
+
"snake case" version of the property:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
file_types %w(rb rbx rjs Rakefile rake cgi fcgi gemspec irbrc capfile Gemfile)
|
57
|
+
first_line_match %r'^#!/.*\bruby'
|
58
|
+
folding_start_marker %r:(?x)^
|
59
|
+
...
|
60
|
+
:
|
61
|
+
folding_stop_marker %r/(?x)
|
62
|
+
...
|
63
|
+
/
|
64
|
+
key_equivalent "^~R" # TextMate only
|
65
|
+
uuid "E00B62AC-6B1C-11D9-9B1F-000D93589AF6" # TextMate only
|
66
|
+
```
|
67
|
+
|
68
|
+
There are 3 exceptions:
|
69
|
+
|
70
|
+
- `scopeName` is not available, since it is specified in the arguments of the `language` method.
|
71
|
+
|
72
|
+
- `patterns` is not there: each rule inside patterns= corresponds to a `rule` block.
|
73
|
+
|
74
|
+
- `repository` is not there either: each fragment inside repository= corresponds to a `fragment`
|
75
|
+
block.
|
76
|
+
|
77
|
+
Rules are specified in `rule` blocks, the scope name being the (optional) argument of the
|
78
|
+
`rule` method:
|
79
|
+
|
80
|
+
```
|
81
|
+
{ name = 'string.unquoted.here-doc';
|
82
|
+
begin = '<<(\w+)'; // match here-doc token
|
83
|
+
end = '^\1$'; // match end of here-doc
|
84
|
+
}
|
85
|
+
```
|
86
|
+
|
87
|
+
becomes:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
rule 'string.unquoted.here-doc' do
|
91
|
+
from %r/<<(\w+)/ # match here-doc token
|
92
|
+
to %r/^§1$/ # match end of here-doc
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
`begin` and `end` being reserved words in Ruby, they are replaced by `from` and `to` (and
|
97
|
+
`applyEndPatternLast` is just `to_last`).
|
98
|
+
|
99
|
+
Notice also how back-references in `to` are noted with `§` instead of `\\`:
|
100
|
+
otherwise, the corresponding Ruby Regexp would be invalid.
|
101
|
+
|
102
|
+
Finally, the leading `%r` is to avoid syntactic warnings from Ruby.
|
103
|
+
One could also write (matter of taste):
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
rule 'string.unquoted.here-doc' do
|
107
|
+
from(/<<(\w+)/)
|
108
|
+
to(/^§1$/)
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
Or, if you accept warnings (frown):
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
rule 'string.unquoted.here-doc' do
|
116
|
+
from /<<(\w+)/
|
117
|
+
to /^§1$/
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
Nesting is performed by nesting rules, without patterns=:
|
122
|
+
|
123
|
+
```
|
124
|
+
{ begin = '<%'
|
125
|
+
end = '%>'
|
126
|
+
patterns = (
|
127
|
+
{ match = '\b(def|end)\b'; … },
|
128
|
+
…
|
129
|
+
);
|
130
|
+
};
|
131
|
+
```
|
132
|
+
|
133
|
+
becomes:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
rule do
|
137
|
+
from %r'<%'
|
138
|
+
to %r'%>'
|
139
|
+
rule do
|
140
|
+
match %r'\b(def|end)\b'
|
141
|
+
…
|
142
|
+
end
|
143
|
+
…
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
`contentName` is `content_scope`:
|
148
|
+
|
149
|
+
```
|
150
|
+
{ begin = '#if 0(\s.*)?$'; end = '#endif';
|
151
|
+
contentName = 'comment.block.preprocessor';
|
152
|
+
};
|
153
|
+
```
|
154
|
+
|
155
|
+
becomes:
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
rule do
|
159
|
+
from %r'#if 0(\s.*)?$'
|
160
|
+
to %r'#endif'
|
161
|
+
content_scope 'comment.block.preprocessor'
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
`captures`, `beginCaptures`, `endCaptures` are specified as a final hash argument
|
166
|
+
for `match`, `from` and `to`, respectively:
|
167
|
+
|
168
|
+
```
|
169
|
+
{ match = '(@selector\()(.*?)(\))';
|
170
|
+
captures = {
|
171
|
+
1 = { name = 'storage.type.objc'; };
|
172
|
+
3 = { name = 'storage.type.objc'; };
|
173
|
+
};
|
174
|
+
};
|
175
|
+
```
|
176
|
+
|
177
|
+
becomes:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
rule do
|
181
|
+
match %r'(@selector\()(.*?)(\))',
|
182
|
+
1 => 'storage.type.objc',
|
183
|
+
2 => 'storage.type.objc'
|
184
|
+
end
|
185
|
+
```
|
186
|
+
|
187
|
+
Captures that are common to `from` and `to` can be specified with `both`:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
rule 'comment.block.documentation.ruby' do
|
191
|
+
from %r/^=begin/
|
192
|
+
to %r/^=end/
|
193
|
+
both 0 => 'punctuation.definition.comment.ruby'
|
194
|
+
end
|
195
|
+
```
|
196
|
+
|
197
|
+
`include` is specified without patterns=:
|
198
|
+
|
199
|
+
```
|
200
|
+
{ begin = '<\?(php|=)?'; end = '\?>'; patterns = (
|
201
|
+
{ include = "source.php"; }
|
202
|
+
);
|
203
|
+
}
|
204
|
+
```
|
205
|
+
|
206
|
+
becomes:
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
rule do
|
210
|
+
from %r'<\?(php|=)?'
|
211
|
+
to %r'\?>'
|
212
|
+
include 'source.php'
|
213
|
+
end
|
214
|
+
```
|
215
|
+
|
216
|
+
Finally, repository entries use `fragment`:
|
217
|
+
|
218
|
+
```
|
219
|
+
patterns = (
|
220
|
+
{ name = 'string.unquoted.qq.perl';
|
221
|
+
begin = 'qq\('; end = '\)'; patterns = (
|
222
|
+
{ include = '#qq_string_content'; },
|
223
|
+
);
|
224
|
+
},
|
225
|
+
…
|
226
|
+
); // end of patterns
|
227
|
+
repository = {
|
228
|
+
qq_string_content = {
|
229
|
+
begin = '\('; end = '\)'; patterns = (
|
230
|
+
{ include = '#qq_string_content'; },
|
231
|
+
);
|
232
|
+
};
|
233
|
+
};
|
234
|
+
```
|
235
|
+
|
236
|
+
becomes:
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
rule 'string.unquoted.qq.perl' do
|
240
|
+
from %r'qq\('
|
241
|
+
to %r'\)'
|
242
|
+
include '#qq_string_content'
|
243
|
+
end
|
244
|
+
|
245
|
+
fragment :qq_string_content
|
246
|
+
rule do
|
247
|
+
from %r'\('
|
248
|
+
to %r'\)'
|
249
|
+
include '#qq_string_content'
|
250
|
+
end
|
251
|
+
end
|
252
|
+
```
|
253
|
+
|
254
|
+
|
255
|
+
## Commands
|
256
|
+
|
257
|
+
Commands are specified in a `commands` block by the `item` method:
|
258
|
+
|
259
|
+
```json
|
260
|
+
// in Default.sublime-commands:
|
261
|
+
{ "caption": "Word Wrap: Toggle", "command": "toggle_setting", "args": {"setting": "word_wrap"} },
|
262
|
+
{ "caption": "Convert Case: Upper Case", "command": "upper_case" },
|
263
|
+
{ "command": "toggle_comment", "args": {"block": false}, "caption": "Toggle Comment" },
|
264
|
+
```
|
265
|
+
|
266
|
+
becomes:
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
commands 'Default' do
|
270
|
+
item 'Word Wrap: Toggle', toggle_setting("word_wrap")
|
271
|
+
item 'Convert Case: Upper Case', upper_case
|
272
|
+
item 'Toggle Comment', toggle_comment(block: false)
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
Commands are transcribed as Ruby method invocations. If the first argument key is the same
|
277
|
+
as the last word of the command, it is not written: `toggle_setting(setting: "word_wrap")`
|
278
|
+
is transcribed as `toggle_setting("word_wrap")`. This is the case everywhere ST commands are
|
279
|
+
specified (mouse & key bindings, macros).
|
280
|
+
|
281
|
+
## Menus
|
282
|
+
|
283
|
+
Menus are specified in a `menu` block with the `item` method, that accepts an optional
|
284
|
+
block to define submenus:
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
menu 'Main' do
|
288
|
+
item '&File', id: 'file' do
|
289
|
+
item '&New File', new_file
|
290
|
+
item '&Open File…', prompt_open_file, platform: '!OSX'
|
291
|
+
item 'Open Folder…', prompt_open_folder, platform: '!OSX'
|
292
|
+
item 'Open…', prompt_open, platform: 'OSX'
|
293
|
+
item 'Open &Recent' do
|
294
|
+
item 'Reopen Closed File', reopen_last_file
|
295
|
+
item '-'
|
296
|
+
0.upto(7) { |i| item open_recent_file(index: i) }
|
297
|
+
item '-'
|
298
|
+
0.upto(7) { |i| item open_recent_folder(index: i) }
|
299
|
+
item '-'
|
300
|
+
item 'Clear Items', clear_recent_files
|
301
|
+
end
|
302
|
+
...
|
303
|
+
end
|
304
|
+
end
|
305
|
+
```
|
306
|
+
|
307
|
+
The `mnemonic` option can be specified, but is also obtained by prefixing
|
308
|
+
the letter by `&` in the caption (use `&&` to obtain the character `&`).
|
309
|
+
|
310
|
+
## Mouse Bindings
|
311
|
+
|
312
|
+
Mouse bindings use the `mousemap` method with a block:
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
mousemap 'Default (Windows)' do
|
316
|
+
|
317
|
+
click 'button1', down: drag_select
|
318
|
+
click 'ctrl+button1', down: drag_select(additive: true)
|
319
|
+
click 'alt+button1', down: drag_select(subtractive: true)
|
320
|
+
click 'shift+button1', down: drag_select(extend: true)
|
321
|
+
click 'shift+ctrl+button1', down: drag_select(additive: true, extend: true)
|
322
|
+
click 'shift+alt+button1', down: drag_select(subtractive: true, extend: true)
|
323
|
+
click2 'button1', down: drag_select(by: "words")
|
324
|
+
click2 'ctrl+button1', down: drag_select(by: "words", additive: true)
|
325
|
+
click2 'alt+button1', down: drag_select(by: "words", subtractive: true)
|
326
|
+
click3 'button1', down: drag_select(by: "lines")
|
327
|
+
click3 'ctrl+button1', down: drag_select(by: "lines", additive: true)
|
328
|
+
click3 'alt+button1', down: drag_select(by: "lines", subtractive: true)
|
329
|
+
click 'shift+button2', down: drag_select(by: "columns")
|
330
|
+
click 'shift+ctrl+button2', down: drag_select(by: "columns", additive: true)
|
331
|
+
click 'shift+alt+button2', down: drag_select(by: "columns", subtractive: true)
|
332
|
+
click 'button3', down: drag_select(by: "columns")
|
333
|
+
click 'ctrl+button3', down: drag_select(by: "columns", additive: true)
|
334
|
+
click 'alt+button3', down: drag_select(by: "columns", subtractive: true)
|
335
|
+
click1 'button2+button1', down: drag_select, up: expand_selection(to: "line")
|
336
|
+
click2 'button2+button1', up: expand_selection_to_paragraph
|
337
|
+
click3 'button2+button1', up: select_all
|
338
|
+
click 'button4', up: prev_view
|
339
|
+
click 'button5', up: next_view
|
340
|
+
click 'button2+scroll_down', up: next_view
|
341
|
+
click 'button2+scroll_up', up: prev_view
|
342
|
+
click 'ctrl+scroll_down', up: decrease_font_size
|
343
|
+
click 'ctrl+scroll_up', up: increase_font_size
|
344
|
+
click 'button2', up: context_menu
|
345
|
+
|
346
|
+
end
|
347
|
+
```
|
348
|
+
|
349
|
+
The method `click` is for a single click (`click1` is also valid), while
|
350
|
+
`click2` is for a double-click and `click3` is for a triple-click. `press_command` is the
|
351
|
+
`down` option, `command` is the `up` option.
|
352
|
+
|
353
|
+
The buttons and modifiers can be renamed with `button_names`:
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
mousemap 'Default (Windows)' do
|
357
|
+
|
358
|
+
button_names(
|
359
|
+
'left' => 'button1',
|
360
|
+
'right' => 'button2',
|
361
|
+
'middle' => 'button3',
|
362
|
+
'back' => 'button4',
|
363
|
+
'forward' => 'button5',
|
364
|
+
'down' => 'scroll_down',
|
365
|
+
'up' => 'scroll_up',
|
366
|
+
'win' => 'super'
|
367
|
+
)
|
368
|
+
|
369
|
+
click 'left', down: drag_select
|
370
|
+
click 'ctrl+left', down: drag_select(additive: true)
|
371
|
+
click 'alt+left', down: drag_select(subtractive: true)
|
372
|
+
click 'shift+left', down: drag_select(extend: true)
|
373
|
+
click 'shift+ctrl+left', down: drag_select(additive: true, extend: true)
|
374
|
+
click 'shift+alt+left', down: drag_select(subtractive: true, extend: true)
|
375
|
+
click2 'left', down: drag_select(by: "words")
|
376
|
+
click2 'ctrl+left', down: drag_select(by: "words", additive: true)
|
377
|
+
click2 'alt+left', down: drag_select(by: "words", subtractive: true)
|
378
|
+
click3 'left', down: drag_select(by: "lines")
|
379
|
+
click3 'ctrl+left', down: drag_select(by: "lines", additive: true)
|
380
|
+
click3 'alt+left', down: drag_select(by: "lines", subtractive: true)
|
381
|
+
click 'shift+right', down: drag_select(by: "columns")
|
382
|
+
click 'shift+ctrl+right', down: drag_select(by: "columns", additive: true)
|
383
|
+
click 'shift+alt+right', down: drag_select(by: "columns", subtractive: true)
|
384
|
+
click 'middle', down: drag_select(by: "columns")
|
385
|
+
click 'ctrl+middle', down: drag_select(by: "columns", additive: true)
|
386
|
+
click 'alt+middle', down: drag_select(by: "columns", subtractive: true)
|
387
|
+
click1 'right+left', down: drag_select, up: expand_selection(to: "line")
|
388
|
+
click2 'right+left', up: expand_selection_to_paragraph
|
389
|
+
click3 'right+left', up: select_all
|
390
|
+
click 'back', up: prev_view
|
391
|
+
click 'forward', up: next_view
|
392
|
+
click 'right+down', up: next_view
|
393
|
+
click 'right+up', up: prev_view
|
394
|
+
click 'ctrl+down', up: decrease_font_size
|
395
|
+
click 'ctrl+up', up: increase_font_size
|
396
|
+
click 'right', up: context_menu
|
397
|
+
|
398
|
+
end
|
399
|
+
```
|
400
|
+
|
401
|
+
## Key Bindings
|
402
|
+
|
403
|
+
Key bindings are defined inside a `keymap` block. Each binding is specified
|
404
|
+
by the `bind` method, and the context by methods equivalent to `if`, `and`
|
405
|
+
and `or`. Because the latters are reserved in Ruby, `conditionals` gives
|
406
|
+
the method names used, which default to their French equivalent (`si`, `et`
|
407
|
+
and `ou`). You can also leave out `conditionals`, in which case you have to
|
408
|
+
use `_if`, `_and` and `_or`.
|
409
|
+
|
410
|
+
ST has three types of the context conditions:
|
411
|
+
|
412
|
+
- Just a key:
|
413
|
+
```json
|
414
|
+
{ "key": "auto_complete_visible" }
|
415
|
+
```
|
416
|
+
becomes:
|
417
|
+
```ruby
|
418
|
+
si auto_complete_visible
|
419
|
+
```
|
420
|
+
|
421
|
+
- A key and an operand.
|
422
|
+
|
423
|
+
- If the operand is a string, it is rendered as "== symbol"
|
424
|
+
```json
|
425
|
+
{"key": "panel", "operand": "find"}
|
426
|
+
```
|
427
|
+
becomes:
|
428
|
+
```ruby
|
429
|
+
si panel == :find
|
430
|
+
```
|
431
|
+
|
432
|
+
- Otherwise, it is rendered with `is`:
|
433
|
+
```json
|
434
|
+
{ "key": "setting.auto_complete_commit_on_tab", "operand": false }
|
435
|
+
```
|
436
|
+
becomes:
|
437
|
+
```ruby
|
438
|
+
si setting.auto_complete_commit_on_tab is false
|
439
|
+
```
|
440
|
+
|
441
|
+
- A key, an operator and an operand: this is rendered as a Ruby condition, with
|
442
|
+
the following operators:
|
443
|
+
```
|
444
|
+
equal ==
|
445
|
+
not_equal !=
|
446
|
+
regex_contains =~
|
447
|
+
not_regex_contains !~
|
448
|
+
regex_match .regex_match # comment
|
449
|
+
not_regex_match .not_regex_match # comment
|
450
|
+
```
|
451
|
+
The comment is 'could use =~ (resp. !~) with \A and \z' (correct me if I'm wrong).
|
452
|
+
|
453
|
+
Example:
|
454
|
+
|
455
|
+
```ruby
|
456
|
+
keymap 'Default (Windows)' do
|
457
|
+
|
458
|
+
conditionals if: 'si', and: 'et', or: 'ou'
|
459
|
+
|
460
|
+
bind 'esc', single_selection
|
461
|
+
si num_selections != 1
|
462
|
+
bind 'esc', clear_fields
|
463
|
+
si has_next_field ## true
|
464
|
+
ou has_prev_field ## true
|
465
|
+
bind 'esc', hide_panel(cancel: true)
|
466
|
+
si panel_visible ## true
|
467
|
+
bind 'esc', hide_overlay
|
468
|
+
si overlay_visible ## true
|
469
|
+
bind 'esc', hide_auto_complete
|
470
|
+
si auto_complete_visible ## true
|
471
|
+
|
472
|
+
bind 'tab', insert_best_completion(default: "\t", exact: true)
|
473
|
+
bind 'tab', insert_best_completion(default: "\t", exact: false)
|
474
|
+
si setting.tab_completion ## true
|
475
|
+
bind 'tab', replace_completion_with_next_completion
|
476
|
+
si last_command ## "insert_best_completion"
|
477
|
+
et setting.tab_completion ## true
|
478
|
+
bind 'tab', reindent
|
479
|
+
si setting.auto_indent ## true
|
480
|
+
et all.selection_empty ## true
|
481
|
+
et all.preceding_text =~ /\A\z/
|
482
|
+
et all.following_text =~ /\A\z/
|
483
|
+
bind 'tab', indent
|
484
|
+
si text =~ /\n/
|
485
|
+
bind 'tab', next_field
|
486
|
+
si has_next_field ## true
|
487
|
+
bind 'tab', commit_completion
|
488
|
+
si auto_complete_visible
|
489
|
+
et setting.auto_complete_commit_on_tab
|
490
|
+
|
491
|
+
bind 'shift+tab', insert(characters: "\t")
|
492
|
+
bind 'shift+tab', unindent
|
493
|
+
si setting.shift_tab_unindent ## true
|
494
|
+
ou preceding_text =~ /\A[\t ]*\z/
|
495
|
+
ou text =~ /\n/
|
496
|
+
bind 'shift+tab', prev_field
|
497
|
+
si has_prev_field ## true
|
498
|
+
|
499
|
+
end
|
500
|
+
```
|
501
|
+
|
502
|
+
## Keyboard Definitions
|
503
|
+
|
504
|
+
This feature is experimental. It allows translating keymaps between what you type and what ST sees.
|
505
|
+
For instance, when I type <kbd>ctrl+^</kbd> on my French keyboard on Windows, ST sees
|
506
|
+
<kbd>ctrl+]</kbd>. And when I type <kbd>ctrl+!</kbd>, it sees... nothing!
|
507
|
+
|
508
|
+
So unless your keyboard matches the Sublime Text one, you can describe your keyboard in
|
509
|
+
a keyboard definition file `*.keyboard.rb`, and specify it when importing the package:
|
510
|
+
this will convert the key bindings for your keyboard, adding an instruction
|
511
|
+
`keyboard '(name)'` inside the keymap block of key bindings. There will be a FIXME
|
512
|
+
comment when the keystroke is not available for your keyboard:
|
513
|
+
|
514
|
+
```ruby
|
515
|
+
# FIXME: no equivalent for keystroke: ctrl+break
|
516
|
+
# bind 'ctrl+break', exec(kill: true)
|
517
|
+
```
|
518
|
+
|
519
|
+
The key bindings will be converted back to ST key names when exporting.
|
520
|
+
|
521
|
+
This works well on Windows, but so-so (if at all, I don't remember well) on my Mac with
|
522
|
+
French keyboard. Not tested on Linux.
|
523
|
+
|
524
|
+
To understand the instructions below, look at a French keyboard (from France).
|
525
|
+
|
526
|
+
```ruby
|
527
|
+
keyboard 'AZERTY-fr-FR-v6 (Windows 7)' do
|
528
|
+
|
529
|
+
os 'Windows'
|
530
|
+
|
531
|
+
# modifiers
|
532
|
+
# they will be displayed in the order given here
|
533
|
+
|
534
|
+
add_modifiers 'shift ctrl win alt'
|
535
|
+
|
536
|
+
map_modifier 'win' => 'super'
|
537
|
+
|
538
|
+
# describe the physical keys present on the keyboard
|
539
|
+
#
|
540
|
+
# If the name matches a ST key name, this creates the association,
|
541
|
+
# assuming the key behaves exactly like the ST key when the name
|
542
|
+
# has more than 1 character. When it has only one character,
|
543
|
+
# it is assumed to generate just a chr_event without modifiers,
|
544
|
+
# and to behave like le ST key when modified.
|
545
|
+
|
546
|
+
add_keys 'esc', st_keys: 'escape'
|
547
|
+
add_keys 'f1-f12'
|
548
|
+
add_keys 'print_screen scroll_lock'
|
549
|
+
add_keys 'pause'
|
550
|
+
|
551
|
+
add_keys '²'
|
552
|
+
# we could do this:
|
553
|
+
# add_keys '& é " \' ( - è _ ç à', st_keys: '1 2 3 4 5 6 7 8 9 0'
|
554
|
+
# but I prefer to see 'ctrl+1' rather than 'ctrl+&', for instance, so:
|
555
|
+
add_keys '1 2 3 4 5 6 7 8 9 0'
|
556
|
+
add_keys ') ='
|
557
|
+
add_keys 'backspace tab'
|
558
|
+
add_keys 'a z e r t y u i o p ^ $ enter'
|
559
|
+
add_keys 'q s d f g h j k l m ù *'
|
560
|
+
add_keys '< w x c v b n , ; : !'
|
561
|
+
add_keys 'space context_menu'
|
562
|
+
|
563
|
+
add_keys 'ins del home end pgup pgdn', st_keys: 'insert delete home end pageup pagedown'
|
564
|
+
add_keys 'up down left right' #, display: '↑ ↓ ← →'
|
565
|
+
|
566
|
+
add_keys 'num/ num* num- num+', st_keys: 'keypad_divide keypad_multiply keypad_minus keypad_plus'
|
567
|
+
add_keys 'num0-num9 num.', st_keys: 'keypad0-keypad9 keypad_period'
|
568
|
+
add_keys 'num_enter', st_keys: 'keypad_enter'
|
569
|
+
|
570
|
+
# assign general keystroke substitutions
|
571
|
+
|
572
|
+
map_key '²' => "'" # modifier+² is seen as modifier+'
|
573
|
+
|
574
|
+
map_key ')' => '['
|
575
|
+
map_key '=' => '=' # match
|
576
|
+
|
577
|
+
map_key '^' => ']'
|
578
|
+
map_key '$' => ';'
|
579
|
+
|
580
|
+
map_key 'ù' => '`'
|
581
|
+
map_key '*' => '\\'
|
582
|
+
|
583
|
+
map_key ',' => ',' # match
|
584
|
+
map_key ';' => '.'
|
585
|
+
|
586
|
+
map_key ':' => '/'
|
587
|
+
map_key '!' => nil # modifier+! is not seen
|
588
|
+
|
589
|
+
map_key '<' => nil
|
590
|
+
|
591
|
+
# map some special keystrokes to characters
|
592
|
+
# this does not remove the key mapping, if any:
|
593
|
+
# it therefore means ST sees both a key event and a chr event
|
594
|
+
# 'dead' means it's a dead key
|
595
|
+
|
596
|
+
map_char 'ctrl+alt+2' => '~', dead: true
|
597
|
+
map_char 'ctrl+alt+3' => '#'
|
598
|
+
map_char "ctrl+alt+4" => '{'
|
599
|
+
map_char 'ctrl+alt+5' => '['
|
600
|
+
map_char 'ctrl+alt+6' => '|'
|
601
|
+
map_char 'ctrl+alt+7' => '`', dead: true
|
602
|
+
map_char 'ctrl+alt+8' => '\\'
|
603
|
+
map_char 'ctrl+alt+9' => '^'
|
604
|
+
map_char 'ctrl+alt+0' => '@'
|
605
|
+
map_char 'ctrl+alt+)' => ']'
|
606
|
+
map_char 'ctrl+alt+=' => '}'
|
607
|
+
map_char 'ctrl+alt+e' => '€'
|
608
|
+
map_char 'ctrl+alt+$' => '¤'
|
609
|
+
|
610
|
+
# custom v6 mappings
|
611
|
+
|
612
|
+
map_char 'ctrl+)' => '@'
|
613
|
+
map_char 'ctrl+=' => '#'
|
614
|
+
map_char 'ctrl+^' => '{'
|
615
|
+
map_char 'ctrl+$' => '}'
|
616
|
+
map_char 'ctrl+ù' => '['
|
617
|
+
map_char 'ctrl+*' => ']'
|
618
|
+
map_char 'ctrl+:' => '\\'
|
619
|
+
map_char 'ctrl+!' => '|'
|
620
|
+
|
621
|
+
# OS-reserved keystokes (by default, means ST does not see the keystoke)
|
622
|
+
|
623
|
+
os_action 'win+f1' => 'Windows Help'
|
624
|
+
|
625
|
+
os_action 'win+tab' => 'Aero Flip'
|
626
|
+
os_action 'win+pause' => 'System Properties'
|
627
|
+
os_action 'win+e' => 'Explorer (Computer)'
|
628
|
+
os_action 'win+r' => 'Run'
|
629
|
+
os_action 'win+t' => 'TaskBar'
|
630
|
+
os_action 'win+u' => 'Ease of Access Center (Utility Manager)'
|
631
|
+
os_action 'win+p' => 'Display Choice'
|
632
|
+
os_action 'win+d' => 'Desktop'
|
633
|
+
os_action 'win+f' => 'Find Files'
|
634
|
+
os_action 'win+l' => 'Lock Computer'
|
635
|
+
os_action 'win+m' => 'Minimize All'
|
636
|
+
os_action 'win+shift+m' => 'Restore All'
|
637
|
+
os_action 'win+b' => 'Focus Taskbar Icons'
|
638
|
+
os_action 'win+num+' => 'Magnifier'
|
639
|
+
|
640
|
+
os_action 'ctrl+alt+del' => 'System Menu/Reboot'
|
641
|
+
os_action 'alt+tab' => 'Cycle Running Apps'
|
642
|
+
os_action 'shift+alt+tab' => 'Cycle Back Running Apps'
|
643
|
+
|
644
|
+
os_action 'print_screen' => 'Screen Capture'
|
645
|
+
os_action 'alt+print_screen' => 'Window Capture'
|
646
|
+
|
647
|
+
os_action 'ctrl+esc' => 'Start Menu'
|
648
|
+
os_action 'ctrl+shift+esc' => 'Task Manager'
|
649
|
+
|
650
|
+
os_action 'alt+esc' => 'Next Taskbar Window'
|
651
|
+
os_action 'alt+space' => 'Window Control Menu', key_event: true
|
652
|
+
|
653
|
+
# keystrokes not seen by ST
|
654
|
+
|
655
|
+
map_key 'win+h' => nil
|
656
|
+
map_key 'win+c' => nil
|
657
|
+
map_key 'win+v' => nil
|
658
|
+
|
659
|
+
# strange combinations generating character events
|
660
|
+
|
661
|
+
map_char 'win+shift+d' => 'D'
|
662
|
+
map_char 'ctrl+pause' => "\x03" # ETX
|
663
|
+
|
664
|
+
map_key 'ctrl+pause' => nil # implies that shift+ctrl+pause, alt+ctrl+pause are not seen either
|
665
|
+
|
666
|
+
# numeric keypad (with NumLock on)
|
667
|
+
|
668
|
+
'/*-+'.chars.each do |c|
|
669
|
+
map_char 'num' << c => c
|
670
|
+
map_char 'shift+num' << c => c
|
671
|
+
end
|
672
|
+
|
673
|
+
'0123456789'.chars.each do |c|
|
674
|
+
map_char 'num' << c => c
|
675
|
+
end
|
676
|
+
|
677
|
+
map_char 'num.' => '.'
|
678
|
+
|
679
|
+
%w(0:insert 1:end 2:down 3:pagedown 4:left 5:clear 6:right 7:home 8:up 9:pageup).each do |spec|
|
680
|
+
n, k = spec.split(':')
|
681
|
+
map_key "shift+num#{n}" => k
|
682
|
+
end
|
683
|
+
|
684
|
+
map_key 'shift+num.' => 'delete'
|
685
|
+
|
686
|
+
map_key 'num_enter' => 'enter' # so keypad_enter is not available
|
687
|
+
|
688
|
+
# test: shift+ctrl+keypad5 is undestood as ctrl+clear
|
689
|
+
|
690
|
+
end
|
691
|
+
```
|
692
|
+
|
693
|
+
## Macros
|
694
|
+
|
695
|
+
Macros are rendered by `macro` blocks, like this:
|
696
|
+
|
697
|
+
```ruby
|
698
|
+
macro "Add Line" do
|
699
|
+
move_to "hardeol"
|
700
|
+
insert characters: "\n"
|
701
|
+
end
|
702
|
+
|
703
|
+
macro "Add Line Before" do
|
704
|
+
move_to "hardbol"
|
705
|
+
insert characters: "\n"
|
706
|
+
move by: "lines", forward: false
|
707
|
+
reindent force_indent: false
|
708
|
+
end
|
709
|
+
|
710
|
+
macro "Add Line in Braces" do
|
711
|
+
insert characters: "\n\n"
|
712
|
+
move by: "lines", forward: false
|
713
|
+
move_to "hardeol", extend: false
|
714
|
+
reindent single_line: true
|
715
|
+
end
|
716
|
+
```
|
717
|
+
|
718
|
+
## Settings
|
719
|
+
|
720
|
+
Settings are rendered as `settings` blocks:
|
721
|
+
|
722
|
+
```ruby
|
723
|
+
settings 'Preferences' do
|
724
|
+
|
725
|
+
color_scheme 'Packages/Color Scheme - Default/Monokai.tmTheme'
|
726
|
+
font_size 10
|
727
|
+
font_options []
|
728
|
+
word_separators './\()"\'-:,.;<>~!@#$%^&*|+=[]{}`~?'
|
729
|
+
line_numbers true
|
730
|
+
...
|
731
|
+
auto_complete_triggers [{"selector"=>"text.html", "characters"=>"<"}]
|
732
|
+
...
|
733
|
+
scroll_speed 1.0
|
734
|
+
folder_exclude_patterns %w(.svn .git .hg CVS)
|
735
|
+
...
|
736
|
+
|
737
|
+
end
|
738
|
+
```
|
739
|
+
|
740
|
+
## Themes
|
741
|
+
|
742
|
+
Themes are `theme` blocks. Here is my own coloring theme:
|
743
|
+
|
744
|
+
```ruby
|
745
|
+
theme 'Spartan' do
|
746
|
+
|
747
|
+
# I dont't like code looking like a Christmas tree.
|
748
|
+
# Initially, it was Mac Classic by Chris Thomas.
|
749
|
+
|
750
|
+
author 'Thierry Lambert'
|
751
|
+
uuid '85C02434-2B86-488A-A8F2-E7A9A53385C5'
|
752
|
+
|
753
|
+
white = '#FFFFFF'
|
754
|
+
black = '#000000'
|
755
|
+
brown = '#804000'
|
756
|
+
navy = '#0000A0' # a bit brighter than 'official' navy
|
757
|
+
blue = '#0000FF'
|
758
|
+
red = '#FF0000'
|
759
|
+
green = '#008000'
|
760
|
+
|
761
|
+
gray = '#666666'
|
762
|
+
light_gray = '#888888'
|
763
|
+
pale_gray = '#BFBFBF'
|
764
|
+
blue_gray = '#365F91'
|
765
|
+
|
766
|
+
very_transparent_gray = '#D0D0D040'
|
767
|
+
more_transparent_gray = '#80808020'
|
768
|
+
transparent_gray = '#80808030'
|
769
|
+
less_transparent_gray = '#80808050'
|
770
|
+
|
771
|
+
turquoise_green = '#009070'
|
772
|
+
|
773
|
+
pale_red = '#FFD0D0'
|
774
|
+
|
775
|
+
base_colors \
|
776
|
+
background: white,
|
777
|
+
foreground: black,
|
778
|
+
caret: black,
|
779
|
+
invisibles: pale_gray,
|
780
|
+
line_highlight: transparent_gray,
|
781
|
+
selection: transparent_gray,
|
782
|
+
selection_border: less_transparent_gray,
|
783
|
+
inactive_selection: more_transparent_gray
|
784
|
+
|
785
|
+
item 'Marks', 'mark, bookmark', red
|
786
|
+
|
787
|
+
item 'Comment', 'comment', green
|
788
|
+
|
789
|
+
item 'String', 'string', brown
|
790
|
+
item 'Unquoted String', 'string.unquoted', back: very_transparent_gray
|
791
|
+
# item 'Regular Expression', 'string.regexp', brown
|
792
|
+
item 'Ruby Symbol', 'constant.other.symbol', brown
|
793
|
+
item 'Number', 'constant.numeric', brown
|
794
|
+
item 'Character Escape', 'constant.character.escape', brown, bold
|
795
|
+
item 'Markup: Character Entity', 'constant.character.entity, constant.character.parameter-entity', brown
|
796
|
+
|
797
|
+
item 'Keyword', 'keyword.control, keyword.other, storage', blue
|
798
|
+
item 'Language Constant', 'constant.language', blue
|
799
|
+
item 'Language Variable', 'variable.language', blue
|
800
|
+
|
801
|
+
item 'Library Constant', 'support.constant', navy
|
802
|
+
item 'Operator', 'keyword.operator', navy
|
803
|
+
item 'Other Keyword: Unit', 'keyword.other.unit, keyword.other.ini', navy
|
804
|
+
|
805
|
+
item 'Source in String', 'string source', bold
|
806
|
+
item 'Embedded Source', 'text source', back: '#D0D0A020' # looks bluish otherwise
|
807
|
+
|
808
|
+
item 'Type Name', 'entity.name.type', bold
|
809
|
+
# item 'Inherited Type Name', 'entity.other.inherited-class'
|
810
|
+
# item 'Type Reference', 'support.class'
|
811
|
+
|
812
|
+
item 'Function Name', 'entity.name.function, support.function.any-method', bold
|
813
|
+
item 'Library Function', 'support.function', navy
|
814
|
+
|
815
|
+
item 'Marked Variable', 'variable.other.readwrite, variable.other.macro', navy
|
816
|
+
# item 'Parameter Variable', 'variable.parameter'
|
817
|
+
|
818
|
+
item 'Property Name', 'support.type, support.constant.tm-grammar', navy
|
819
|
+
item 'Section Name', 'entity.name.section', bold
|
820
|
+
|
821
|
+
item 'Preprocessor Line', 'meta.preprocessor', turquoise_green
|
822
|
+
item 'Preprocessor Directive', 'keyword.control.import', turquoise_green, bold
|
823
|
+
|
824
|
+
item 'Deprecated', 'invalid.deprecated', red
|
825
|
+
item 'Deprecated Trailing Whitespace', 'invalid.deprecated.trailing-whitespace', back: pale_red
|
826
|
+
item 'Illegal', 'invalid.illegal', red
|
827
|
+
|
828
|
+
# XML, HTML, CSS
|
829
|
+
item 'ML DOCTYPE', <<-SCOPE, gray
|
830
|
+
meta.tag.sgml.doctype, meta.tag.sgml.doctype entity, meta.tag.sgml.doctype string,
|
831
|
+
meta.tag.preprocessor.xml, meta.tag.preprocessor.xml entity, meta.tag.preprocessor.xml string
|
832
|
+
SCOPE
|
833
|
+
item 'ML Tag Characters', 'meta.tag, declaration.tag', navy
|
834
|
+
item 'ML Tag Name', 'entity.name.tag', navy
|
835
|
+
item 'ML Attribute Name', 'entity.other.attribute-name', navy
|
836
|
+
item 'CSS Selectors', 'source.css entity.name.tag, source.css entity.other.attribute-name', blue
|
837
|
+
|
838
|
+
# Markdown, Textile, etc.
|
839
|
+
item 'Markup: Heading Characters', 'markup.heading', bold
|
840
|
+
# item 'Markup: List', 'markup.list'
|
841
|
+
# item 'Markup: Quote', 'markup.quote'
|
842
|
+
item 'Markup: Raw', 'markup.raw', back: very_transparent_gray
|
843
|
+
item 'Markup: Bold', 'markup.bold', bold
|
844
|
+
item 'Markup: Italic', 'markup.italic', italic
|
845
|
+
item 'Markup: Underline', 'markup.underline', underline
|
846
|
+
# item 'Markup: Deleted', 'markup.deleted'
|
847
|
+
# item 'Markup: Inserted', 'markup.inserted'
|
848
|
+
|
849
|
+
# Subtitles
|
850
|
+
item 'Markup: Number', 'markup.number', pale_gray
|
851
|
+
item 'Markup: Timing', 'markup.timing', light_gray
|
852
|
+
item 'Markup: Timing Arrow', 'markup.punctuation', light_gray
|
853
|
+
|
854
|
+
end
|
855
|
+
```
|
856
|
+
|
857
|
+
## Preferences
|
858
|
+
|
859
|
+
Preferences are specified in `preferences` blocks with a name and a scope:
|
860
|
+
|
861
|
+
```ruby
|
862
|
+
preferences 'Indentation Rules - Comments' => 'comment' do
|
863
|
+
preserve_indent true
|
864
|
+
end
|
865
|
+
|
866
|
+
preferences 'Indentation Rules' => 'source' do
|
867
|
+
decrease_indent_pattern %r'^(.*\*/)?\s*\}[;\s]*$'
|
868
|
+
increase_indent_pattern %r/^.*(\{[^}"']*)$/
|
869
|
+
disable_indent_next_line_pattern %r/^\s*\{[\]})]*\s*$/
|
870
|
+
indent_parens true
|
871
|
+
end
|
872
|
+
|
873
|
+
preferences 'Symbol List' => 'entity.name.function, entity.name.type, meta.toc-list' do
|
874
|
+
show_in_symbol_list true
|
875
|
+
uuid "0A0DA1FC-59DE-4FD9-9A2C-63C6811A3C39"
|
876
|
+
end
|
877
|
+
```
|
878
|
+
|
879
|
+
## Snippets
|
880
|
+
|
881
|
+
Snippets are defined in `snippets` blocks.
|
882
|
+
|
883
|
+
```ruby
|
884
|
+
snippets do
|
885
|
+
# definition statements
|
886
|
+
end
|
887
|
+
```
|
888
|
+
|
889
|
+
### Definition statements:
|
890
|
+
|
891
|
+
- `default_scope 'scope'`
|
892
|
+
|
893
|
+
Sets the default scope for the following definitions.
|
894
|
+
|
895
|
+
- `file_format <format>`
|
896
|
+
|
897
|
+
Defines the file format for the following definitions.
|
898
|
+
Valid formats are `:textmate` and `:sublime_text`.
|
899
|
+
The default is `:sublime_text`.
|
900
|
+
|
901
|
+
- `tab 'tab trigger', 'description', 'content' [, options]`
|
902
|
+
|
903
|
+
Defines a snippet inserted by pressing <kbd>tab</kbd> after the
|
904
|
+
text given by `'tab trigger'`.
|
905
|
+
|
906
|
+
- `key 'key equivalent', 'description', 'content' [, options]`
|
907
|
+
|
908
|
+
Defines a snippet inserted by pressing the keystroke
|
909
|
+
`'key equivalent'` (TextMate only)
|
910
|
+
|
911
|
+
### Options for 'tab' and 'key':
|
912
|
+
|
913
|
+
- `scope: 'scopes'` (the default is given by default_scope)
|
914
|
+
|
915
|
+
- `file: 'base_file_name'` (the default is the description)
|
916
|
+
|
917
|
+
### Options for TextMate only:
|
918
|
+
|
919
|
+
- `key_equivalent: 'key equivalent'` (for 'tab')
|
920
|
+
|
921
|
+
- `tab_trigger: 'tab trigger'` (for 'key')
|
922
|
+
|
923
|
+
- `semantic_class: 'semantic class scope'`
|
924
|
+
|
925
|
+
- `uuid: 'uuid'`
|
926
|
+
|
927
|
+
- `bundle_uuid: 'bundle uuid'`
|