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?
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:"
}
}
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.
Related
I want to add increased number for multi selected caret in visual studio code.
now, When I type it write same words.
But I would like to add increased number by some shortkey so that I don't need to update each one manually.
Preferred result should be like this.
I want to know if this is possible in vs code.
Thanks
You do not need an extension for your use case, although that may make it easier. Here is how to do it without an extension.
Find: (?<=index:\s*)\d+ : this selects only the digits following index: .
Alt+Enter will select all those digits.
Now you can run a simple snippet to replace those digits with an increasing number that could be 0-based or 1-based. Make this keybinding to insert the snippet (in your keybindings.json):
{
"key": "alt+m", // whatever keybinding you want
"command": "editor.action.insertSnippet",
"args": {
"snippet": "$CURSOR_NUMBER" // this will increment and is 1-based
}
}
Trigger the above keybinding. Demo:
Here is an extension approach, using an extension I wrote, Find and Transform, that makes this easy. Make this keybinding:
{
"key": "alt+m", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"find": "(?<=index:\\s*)\\d+", // same find regex
"replace": "${matchNumber}", // this variable will increase, 1-based
"isRegex": true
}
}
That combines the find and replace in one step.
Here is another method so you do not need to hardcode the starting point.
{
"key": "alt+m", // whatever keybinding you want
"command": "findInCurrentFile",
"args": {
"preCommands": [
"editor.action.addSelectionToNextFindMatch",
"editor.action.clipboardCopyAction"
],
"find": "(?<=index:\\s*)\\d+",
"replace": [
"$${",
// whatever math you want to do here
"return Number(${CLIPBOARD}) + ${matchIndex};",
"}$$",
],
"isRegex": true,
"postCommands": "cancelSelection"
}
}
Put the cursor next to or select the number you want as the starting point. The number could be anywhere in the document actually.
You can use the extension Regex Text Generator
Define the following key binding
{
"key": "ctrl+shift+f9", // or any other key combo
"when": "editorTextFocus",
"command": "regexTextGen.generateText",
"args": {
"generatorRegex" : "{{=i+1}}"
}
}
place the multi cursors after index:
press the key combo
accept or modify the inputs
look at the preview, press Enter if you like it, Esc to abort
You can do it with Increment Selection or Text Pastry
Whenever I double click a word in vscode it gets highlighted and selected, as it should. But something else happens sometimes: the whole sentence gets highlighted. Is there a way for me to easily select the whole highlighted sentence?
In the picture I double clicked the word "test", as you can see it is highlighted in a different color, but the whole sentence is also highlighted. Only the word "test" is selected.
(this is in a javascript file but it probably does the same in other formats)
You can use the extension Select By
"selectby.regexes": {
"SelectSentence": {
"backward": "'",
"forward": "'",
"forwardInclude": false,
"backwardInclude": false
}
}
You can use the command palette command: Select text range based on regex and select SelectSentence from the list
Or setup a keybinding
{
"key": "ctrl+shift+alt+f9", // or any other key combo
"when": "editorTextFocus",
"command": "selectby.regex",
"args": ["SelectSentence"]
}
If I comment selected text, only that text is commented in Sublime Text but in VSCode the entire line is commented not just the selected text.
How can I solve this?
You can comment out part of a line by selecting the text and clicking ALT+SHIFT+A - Toggle Block comment option.
With a macro extension macro-commander you can do what I think you want - toggle block comment if you select something less than the entire line, otherwise if you select nothing on the line or the entire line toggle line comment it.
With this in your settings.json:
"macros": {
"commentSelection" : [
{
"javascript": [
"const editor = vscode.window.activeTextEditor;",
"const document = editor.document;",
"const selection = editor.selection;",
// Get the trimmed "word(s)" of the selection
"const word = document.getText(selection).trim();",
// Get the full line of text on the line of the selection
"let lineNumber = selection.start.line;",
"const line = document.lineAt(lineNumber).text.trim();",
// `!word` means the cursor is on the line but nothing selected
"let selectionEqualsEntireLine = !word || (line === word);",
"if (selectionEqualsEntireLine) vscode.commands.executeCommand('editor.action.commentLine');",
"else vscode.commands.executeCommand('editor.action.blockComment');",
]
}
]
and your keybinding to trigger it:
{
"key": "ctrl+;", // use whatever keybinding you wish
"command": "macros.commentSelection"
}
Alternatively, and much simpler, try these keybindings and no macro at all:
{
"key": "ctrl+;",
"command": "editor.action.blockComment",
"when": "editorTextFocus && editorHasSelection"
},
{
"key": "ctrl+;",
"command": "editor.action.commentLine",
"when": "editorTextFocus && !editorHasSelection"
},
The only difference from the macro is if you select all the text - with the macro you would get a line comment, with these keybindings you will get a block comment. I an not sure which version you prefer.
Is there a way to insert or realign comments in vscode like in emacs (i.e. M-;). In emacs a meta-; would insert a new comment at a predefined comment column if there isn't already a comment or realign the comment to the comment column if there is. This would be a nice feature. For instance 'cmd+;' would insert '// ' in javascript code. If there is an extension or keyboard shortcut definition that would do this I'd appreciate hearing about it.
I think I have this working in a macro. You will need the macrosRE extension.
In your settings.json:
"macros": {
"commentTabStop": [
"editor.action.commentLine",
// go to beginning of any text on line
"cursorHome",
// now select all whitespace at beginning of line
{
"command": "cursorMove",
"args": {
"to": "wrappedLineStart",
"select": true
}
},
// set your number of tab stops to place comment
"tab","tab","tab","tab","tab","tab"
]
}
That is longer than I would have hoped but to handle creating a comment on existing text that may or may not have whitespace at the beginning. I am assuming you want all comments to be vertically aligned no matter the amount of leading tabs/space that may have had originally. And to work when creating comments on empty lines.
function fooBar() {
const someVar;
}
becomes
// function fooBar() {
// const someVar;
// }
Unfortunately, the internal indentation within the function is lost. But you could just reformat that part if you uncommented the code later. Select it and Ctrl-K Ctrl-F will fix the internal indentation.
To make the keybinding put this into your keybindings.json:
{
"key": "ctrl+;",
"command": "macros.commentTabStop"
},
I'm trying to do an other sublime text macro.
I will simplify what i would like :
I select a line of code, press the macro key and the macro will add 1 line of text above and 2 more below the selected line.
Ex:
My line of code
I select the line, press macro key and the code may be like :
echo('init');
My line of code
echo('After line');
echo('again after');
I already try the record macro tools but it's not working for the text selected and for go to the line after the selected.
I know how to use key binding it's just for the macro file...
Thanks for your help :)
You don't need a macro for that, you can directly create a keybinding (obviously you can also move it to a macro):
{
"keys": ["ctrl+alt+a"],
"command": "insert_snippet",
"args": {
"contents": "echo('init');\n$SELECTION\necho('After line');\necho('again after');"
},
"context":
[
{ "key": "selection_empty", "operator": "equal", "operand": false }
]
},
Aside: if you only write you macros to trigger them from keybindings you might be interested in the ChainOfCommand package.