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
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'`