sublime_dsl 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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'`