How to insert or realign a line comment at a predefined column in VSCode - visual-studio-code

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"
},

Related

vscode surround text with snippet with correct indentation

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.

Change comment symbol location when using VSCode "Toggle Line Comment" command

Is it possible to customize the location of the comment symbol ('#' when using Python) in VSCode?
For example, if my code is:
def my_func():
value = 1
and I press CMD-/ on line 2, I get:
def my_func():
# value = 1
I would prefer to get:
def my_func():
# value = 1
Is there a way to modify the default behavior?
VSCode: 1.67.1
MacOS: 12.3.1
There is no built-in way to do that. You will need an extension. See https://stackoverflow.com/a/59448448/836330 for a previous answer using a different extension. Here is a better answer using an extension I made in the meantime, Find and Transform. But there are restrictions as noted below.
Make this keybinding (in your keybindings.json):
{
"key": "alt+/", // unfortunately, this cannot be ctrl+/
"command": "findInCurrentFile",
"args": {
{
"key": "alt+r",
"command": "findInCurrentFile",
"args": {
"preCommands": [
"cursorEnd",
"cursorHomeSelect",
"cursorHomeSelect"
],
"replace": "${LINE_COMMENT}${TM_CURRENT_LINE}",
"restrictFind": "line" // works on multiple lines, see the demo
},
"when": "editorLangId == python" // if you want to limit it to a language
},
}
You can use whatever keybinding you want, but not Ctrl+/ because then toggle off will not work.
Ctrl+/ will work to toggle off comments if you do not use it in the keybinding above to add comments.
Note: For this to work well you need to disable the following setting (which I have shown disabled for a particular language, python):
"[python]": {
"editor.comments.insertSpace": false
}
That goes into your settings.json.

Duplicate selected text to a new line VS code?

I already found that the "command": "editor.action.duplicateSelection"
will duplicate the selection right next to it.
I want to duplicate the selected text to a new line. The selection may not be the entire line.
If you are talking about a selection that is less than the entire line, there is no built-in way to duplicate selected text to the next line. It can be done with a macro extension which enables you to run multiple commands at once.
Using the macro extension multi-command try this keybinding (in your keybindings.json):
{
"key": "alt+i", // whatever keybinding you want
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
"editor.action.clipboardCopyAction",
"editor.action.insertLineAfter",
"editor.action.clipboardPasteAction",
{ // to add text after the selection
"command": "type", // you could also put this before the paste command
"args": { "text": " myText here after paste " }
}
]
}
}
That will copy the selected text, insert a blank line after it and paste that text there. Demo:
Demo with adding static text to the duplicated text:
Click File > Preferences > Keyboard Shortcuts:
Look for the Copy Line Down keyboard shortcut.

How can I add a comment to either a selection or the entire line with one keybinding like the sublime keyboard shortcut?

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.

how to create sublime text macro with selected line of code?

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.