Customize “wrap” characters in Sublime Text

rubysublime-textsublime-text-2sublime-text-3

In Sublime Text, highlighting any text and pressing any of the following symbols:

'
"
(
{
[

will cause the entire highlighted section(s) to be surrounded by the key you pressed (or its matching symbol). Is there an option to add more characters to this list? I would fairly often use | and ` in Ruby development.

Best Answer

As it so happens, I've already set up the keybindings for backticks (`), so modifying them for pipes | should be easy. To do this, open Preferences -> Key Bindings-User. If the file is empty, add opening and closing square brackets [] on separate lines, and paste the following in between them:

// Auto-pair backticks
{ "keys": ["`"], "command": "insert_snippet", "args": {"contents": "`$0`"}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|>|$|;)", "match_all": true },
        { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[`a-zA-Z0-9_]$", "match_all": true },
        { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.double", "match_all": true }
    ]
},
{ "keys": ["`"], "command": "insert_snippet", "args": {"contents": "`${0:$SELECTION}`"}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true }
    ]
},
{ "keys": ["`"], "command": "move", "args": {"by": "characters", "forward": true}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^`", "match_all": true }
    ]
},
{ "keys": ["backspace"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Delete Left Right.sublime-macro"}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
        { "key": "preceding_text", "operator": "regex_contains", "operand": "`$", "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^`", "match_all": true }
    ]
},

For pipe characters, you'll need to modify some of the regexes slightly, as | has a special meaning. The following works for me:

// Auto-pair pipes in Ruby
{ "keys": ["|"], "command": "insert_snippet", "args": {"contents": "|$0|"}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^(?:\t| |\\)|]|\\}|>|$|;)", "match_all": true },
        { "key": "preceding_text", "operator": "not_regex_contains", "operand": "[\\|a-zA-Z0-9_]$", "match_all": true },
        { "key": "eol_selector", "operator": "not_equal", "operand": "string.quoted.double", "match_all": true },
        { "key": "selector", "operator": "equal", "operand": "source.ruby", "match_all": true }
    ]
},
{ "keys": ["|"], "command": "insert_snippet", "args": {"contents": "|${0:$SELECTION}|"}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": false, "match_all": true },
        { "key": "selector", "operator": "equal", "operand": "source.ruby", "match_all": true }
    ]
},
{ "keys": ["|"], "command": "move", "args": {"by": "characters", "forward": true}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^\\|", "match_all": true },
        { "key": "selector", "operator": "equal", "operand": "source.ruby", "match_all": true }
    ]
},
{ "keys": ["backspace"], "command": "run_macro_file", "args": {"file": "res://Packages/Default/Delete Left Right.sublime-macro"}, "context":
    [
        { "key": "setting.auto_match_enabled", "operator": "equal", "operand": true },
        { "key": "selection_empty", "operator": "equal", "operand": true, "match_all": true },
        { "key": "preceding_text", "operator": "regex_contains", "operand": "\\|$", "match_all": true },
        { "key": "following_text", "operator": "regex_contains", "operand": "^\\|", "match_all": true },
        { "key": "selector", "operator": "equal", "operand": "source.ruby", "match_all": true }
    ]
}

You'll notice that I added the selector source.ruby to the | keybindings - you can remove or change this if you want to use it in other files besides Ruby code. I didn't add it to the backtick code because they can be used in other syntaxes - Python and Markdown being the ones that spring to my mind first.