markdownsublimetext2multimarkdown

Sublime Text 2--Doubled Autopaired Characters


I'm a newish Sublime Text 2 user, using it largely for Markdown/MultiMarkdown at this point. In my writing workflow, I use _underscore_ pairing for all italics, and **double asterisk** pairing for all bold text. I've taken some of the basic code for autpairing and gotten it to pair double asterisks after I type a single asterisks. This is the exact behavior I want, but I've been unable to get the normal pairing-backspace functions to work.

With other autopaired characters, such as [], hitting backspace after typing the opening character will delete both paired characters. But when I backspace one of these double asterisk pairs, it deletes only one of the four asterisks (leaving me with ***).

Any one know if this is possible? For bonus points, I'd love to have the second keybinding snippet (which allows you to hit tab and skip to the end of an autopair) allow me to tab to the end of **TEXT**.

// Auto-pair double asterisks (type a single asterisk to invoke)
{ "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": "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 }
    ]
},
//Tab skips to end of autopaired characters
{ "keys": ["tab"], "command": "move", "args": {"by": "characters", "forward": true},
  "context": [ { "key": "selection_empty", "operator": "equal", "operand": true },
            { "key": "preceding_text", "operator": "not_regex_match", "operand": "[[:space:]]*", "match_all": true },
            { "key": "following_text", "operator": "regex_contains", "operand": "^[\"'\\)\\}\\]\\_]", "match_all": true },
            { "key": "auto_complete_visible", "operator": "equal", "operand": false },
            { "key": "has_next_field", "operator": "equal", "operand": false } ] },

Solution

  • * is a special character for regular expression, so you need to escape it. The backspace key should be something like this:

    "keys": ["backspace"], "command": "run_macro_file", "args": {"file": "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 }
    ]
    

    Notice the \\*$ in preceding_text key regexp operand, and ^\\* in following_text key regexp operand. Anyway, you'll have to hit backspace twice, to delete both *: I don't think it is possible to delete both at once.

    The snippet you need should be something like this:

    <snippet>
        <content><![CDATA[
    **${1:TEXT}** ${2:}
    ]]></content>
        <tabTrigger>your_snippet</tabTrigger>
    </snippet>
    

    You should change your_snippet with any text you want as a trigger.