I am trying to create a snippet that surrounds the selected text with try..except
block. This is what I have in keybindings.json file:
{
"key": "ctrl p'",
"command": "editor.action.insertSnippet",
"when": "editorHasSelection",
"args": {
"snippet": "try:\r\n\t${TM_SELECTED_TEXT}\r\nexcept BaseException as ex:"
}
}
This works for most part except that if I select the entire line of indented code, it inserts try at the beginning of the line. I want it to behave like Command /
which adds #
right before where the text starts.
How do I make my snippet behave like that?
CodePudding user response:
You have to insert a possible whitespace in front of each line and remove the whitespace on the middle line:
{
"key": "ctrl p'",
"command": "editor.action.insertSnippet",
"when": "editorHasSelection",
"args": {
"snippet": "${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}try:\r\n${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}\t${TM_SELECTED_TEXT/^[ \\t]*(.*)$/$1/}\r\n${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}except BaseException as ex:"
}
}
CodePudding user response:
Dang, it took a while but here is something pretty simple that I think works.
First, make this snippet (in some snippets file):
"try except": {
// "scope": "python",
// "prefix": "tryWrap", // if you want it
"body": [
"${1:${TM_SELECTED_TEXT/^([ \\t]*)[\\s\\S]*$/$1/}}try:",
"${TM_SELECTED_TEXT/^(.*?)$(\\r?\\n)?/\t$1$2/gm}", // note the 'g' flag !!!
"$1except BaseException as ex:"
]
}
and then this keybinding (in your keybindings.json
):
{
"key": "alt q",
"command": "editor.action.insertSnippet",
"args": {
"name": "try except",
}
}
That middle line of the snippet:
"${TM_SELECTED_TEXT/^(.*?)$(\\r?\\n)?/\t$1$2/gm}"
will actually run once for each line of your selection, because the match is from ^
to the end of the same line and because of the global g
flag. So it'll keep running as long as it finds matches in your entire selection.
The leading whitespace is computed by
${1:${TM_SELECTED_TEXT/^([ \\t]*)[\\s\\S]*$/$1/}}
which will be the first line of your selection. It isn't computed for each line (although it probably could be, it would just be unnecssarily messy). So don't select part of the leading white space of that first line of the selection - actually it seems to work fine as long as select whole tabs worth of that leading white space, just not an extra space. It is easy to do it right.
@rioV8's snippet works for me (for single lines only it seems) but it could be simplified a bit. I upvoted it.
Note that 3 parts of the snippet are identical: ${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}
So to simplify that resulting value (the whitespace before the selected text) can be stored in a value and reused. See this:
${1:${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}} // wrapped in tabstop 1
Now you can just use $1
in any other place you want that same value.
"snippet": "${1:${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}}try:\r\n$1\t${TM_SELECTED_TEXT/^[ \\t]*(.*)$/$1/}\r\n$1except BaseException as ex:"
See there are two $1
's not part of a transform, like try:\r\n$1\t
: that $1
will be your computed whitespace from ${1:${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}}
Also, this part: ${TM_SELECTED_TEXT/^[ \\t]*(.*)$/$1/}
can be simplified to
${TM_SELECTED_TEXT/^[ \\t]*//}
which matches the leading white space before the text and replaces that white space with nothing.
Result:
"snippet": "${1:${TM_SELECTED_TEXT/^([ \\t]*).*$/$1/}}try:\r\n$1\t${TM_SELECTED_TEXT/^[ \\t]*//}\r\n$1except BaseException as ex:"
This is just a little cleaner and less prone to typos. You just have to do one tab or escape at the end to finish.