Wrap Selection Snippet on Visual Studio Code (vscode) - visual-studio-code

I want to create an snippet when triggered it will surround the given text. Currently my snippet is:
{
"Function Creator Helper": {
"prefix": "_w",
"body": [
"public function $TM_SELECTED_TEXT () {",
" $1",
"}",
],
"description": "Creates a function given the text selection"
}
}
This results on:
What I do is:
Select the text.
Write the prefix (_w)
Press Tab
This results on:
public function () {
}
But I was expecting
public function person () {
}
Any ideas on how can I make this snippet or how can I triggered it correctly?

See https://stackoverflow.com/a/48676522/836330 Your example will work, as of vscode v1.49, as you have it. Vscode snippets have been updated to "remember" your selected text even though you seemingly overwrite it with your snippet prefix.
Older answer:
You can use $TM_SELECTED_TEXT if you trigger it with a hotkey:
{
"key": "cmd+k 1",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
// "langId": "csharp",
"name": "Function Creator Helper"
}
}

The currently selected text is exposed as ${TM_SELECTED_TEXT}, not $TM_SELECTED_TEXT.
edit: As commented below, this is not the case for this particular use-case

I was just struggling with this myself. In order to get this to work, the only thing you have to do is press F1, run the Insert Snippet command and then select your snippet from the list.

${TM_SELECTED_TEXT} does not work for me either.
${selectedText} has been added as a Snippet Editor Variable:
https://github.com/Microsoft/vscode/pull/39483#issuecomment-383552677
Example:
"JS Block Quote": {
"prefix": "c2",
"body": [
"/* ${selectedText} */",
],
"description": "JS Block Quote"
}
At this time it is not correctly documented:
https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables
NOTE: In a multi-line selection, ${selectedText} is truncated to the first line. An alternative is to use the the clipboard and the ${CLIPBOARD} variable.
An extra step :(

from Mitches example:
"JS Block Quote": {
"prefix": "c2",
"body": [
"/* $TM_SELECTED_TEXT */",
],
"description": "JS Block Quote" }
from the article: https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables
the docs must have been ahead of the release.
This works fine in vscode v1.30.2

If somebody wants to know, it works like that for me :
I created two same snippet which only matches when I'm in html or php file (just create two snippets files in your snippets folder "php.json" and "html.json" it works for any languages) and added this code inside :
"unicommentary": {
"prefix": "unicommentary",
"body": "<?php /* ${TM_SELECTED_TEXT} */ ?> ${0}",
"description": "Creates a universal comment to disable both html and php."
}
The ${TM_SELECTED_TEXT} tag works when you select some text and trigger your snippet by the Insert Snippet command, you can't just write on selected text.
When you want to use this, select the text you want in your snippet, press Ctrl + Shift + P and select Insert snippet then, type the name of your snippet, press enter and there you go !

Related

Can I trigger a code snippet programmatically in an extension?

I have an extension that provides some snippets. I want to add a command that creates a new file with the snippet automatically triggered for the user. The idea is to get the user to edit the tabstops immediately without any further action. Something like:
Run the command (from the command palette, or a keybinding)
VSCode opens a new file with the snippet already evaluated and waiting on the first tabstop for user input
I have scouted the APIs but I haven't found anything to trigger a snippet. The most relevant APIs are those about the CompletionItemProvider, which can be used to provide a snippet.
Does anybody know how to trigger/expand a snippet automatically?
There is also an insertSnippet method on the TextEditor, see https://code.visualstudio.com/api/references/vscode-api#TextEditor.
So you could do this:
const editor = vscode.window.activeTextEditor;
// build your snippet with the SnippetString methods
const snippet = new vscode.SnippetString("option1 attr1=${2:Option 1 Placeholder 1} attr2=${3:Option 1 Placeholder 2}");
await editor.insertSnippet(snippet);
You can also run the command insertSnippet like this:
// body of snippet here is exactly as you would write it in a keybinding
await vscode.commands.executeCommand("editor.action.insertSnippet", { "snippet": "${CURRENT_YEAR}-${CURRENT_MONTH}-${CURRENT_DATE}T${CURRENT_HOUR}:${CURRENT_MINUTE}:${CURRENT_SECOND}Z" });
// the below uses a pre-existing snippet with a name 'Custom Header'
await vscode.commands.executeCommand("editor.action.insertSnippet", { "name": "Custom Header"});
This last executeCommand can have a reference to a pre-existing snippet that you contributed in your extension. For more see below.
All these commands will insert at the cursor with the snippets in the first tabstop position as you wanted.
Contributing snippets in your extension:
In your package.json:
"contributes": {
"snippets": [
{
"language": "javascript",
"path": "./snippets/javascript.json"
}
]
}
You create a folder named snippets in your extension and a file named javascript.json for javascript snippets. And then use the usual snippet format in that file, like:
{
"Custom Header2": { // use this 'name'
"prefix": "reactpure",
"body": [
"import React from 'react';",
"import PropTypes from 'prop-types';",
"import './${1:ComponentName}.module.css';",
"const ${1:ComponentName} = ({ ${2:propValue=[] } }) => (",
"<${3:rootelement}>${4:content}</${3:rootelement}>",
")",
"${1:ComponentName}.propTypes = {",
"${5:propValue}: PropTypes.string",
"};",
"export default ${1:ComponentName};",
"$0"
],
"description": "Create a react pure component"
}
}
Then you can use that name in your extension
// using an extension-contributed snippet
await vscode.commands.executeCommand("editor.action.insertSnippet", { "name": "Custom Header2"});
``

How to tab complete to a new snippet while already in a snippet?

If I'm already in a snippet and I press tab, I'll proceed to the next placeholder. However, if I'm already in a placeholder and I've typed a prefix that should trigger another snippet, if I press tab, I proceed to the next placeholder instead of expanding the prefix I just typed. Is there a way to expand the prefix I just typed within a snippet?
Here's an example:
"test": {
"prefix": "t",
"body": "|${1}|${2}",
},
"text": {
"prefix": "a",
"body": "asdfghjkl",
}
If I type t I'll get to: ||
If I type a in the first placeholder and press tab I'll get: |a| where my cursor is at the ${2} placeholder
I would like to get: |asdfghjkl| instead
The main problem is that after you type a you have |a| and vscode will not recognize that a as a snippet prefix. It looks like |a to vscode. So if you actually made your second prefix to be | that would be recognized as the prefix, like:
"text": {
"prefix": "|a",
"body": "asdfghjkl",
}
You still have to Ctrl+Space to show suggestions and Enter to accept the suggestion. A Tab there would just go to the next tabstop
Alternatively, if you could insert a space like
"test4": {
"prefix": "t",
"body": "| ${1}|${2}", // space added here
},
then you wouldn't have to modify the second snippet.
Also, make sure that you have
Editor > Suggest: Snippets Prevent Quick Suggestions
disabled (enabled is the default) so you can trigger the suggestions within the first snippet - but you have to manually trigger them yourself with Ctrl+Space as mentioned above.

VSCode snippets refresh required after change?

After changeing an user snippet I,d like to use it.
Is there any other way to update the snippets besides restarting VSCode?
Simply save the snippet file.
If still doesn't works, do Ctrl +Shift + P, type reload window and press enter.
I had this problem when I put my snippet in the wrong Snippet file. For example, I wanted to write a new snippet for creating a React Funcition Component like so:
{
// Place your snippets for typescriptreact here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
// "Print to console": {
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"React Function Component": {
"prefix": "reactfc",
"body": [
"export type ${2:Props} = {",
"};",
"",
"export const ${1:Component}: React.FC<${2:Props}> = props => {",
" return (",
" <>$0</>",
" );",
"};"
],
"description": "Create a new React Function Component with types"
}
}
But I accidentally put it in the typescript.json snippets file instead of the typescriptreact.json snippets file. Moving it into the right snippets file made it be picked up correctly. That could be the problem here.
At any rate, I'm writing this answer here because this is the search that came up when trying to find a solution to this problem.

Visual Studio Code snippet invalid control character

I have the following user snippet:
{
/*
// Place your snippets for JavaScript React here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
"Print to console": {
"prefix": "log",
"body": [
"console.log('$1');",
"$2"
],
"description": "Log output to console"
}
*/
"Small comment": {
"prefix": "//=",
"body": [
"// ===================================",
"// ${1:COMMENT}",
"// ==================================="
],
"description": "Small comment"
}
}
I get the following error on the second body line:
Invalid characters in string. Control characters must be escaped.
I thought that ${1:somestring} was a valid placeholder. What am I doing wrong in constructing this snippet?
I just found this question when looking for an answer, I used snippet generator so assumed the format for each would be the same but without thinking I pasted in code that had tabs in it.
Removing the tabs and used spaces instead for the formatting fixed it for me.
Hope this helps. :)

Using TM_SELECTED_TEXT in my custom snippets

With the November 2016 (version 1.8) release of VSCode Snippet Variables are now supported, specifically TM_SELECTED_TEXT.
This makes me happy as I have used these heavily in both Sublime Text and TextMate.
I can't figure out how to get it to work in VSCode. I've created the snippet they use as an example:
"in quotes": {
"prefix": "inq",
"body": "'${TM_SELECTED_TEXT:${1:type_here}}'"
}
I then enter some text, highlight it and that's where things start to break.
The idea is highlight some text, run the snippet and then ${TM_SELECTED_TEXT:${1:type_here}} is replaced with the highlighted text. The problem I'm having is that to run the snippet you need to type the prefix value (in this case inq) to run the snippet which over-writes your highlighted text which messes everything up.
In Sublime/Textmate I launched the snippet from a keyboard combination which left my text highlighted.
Is there a way, in VSCode, to either make this work as is or launch the snippet from a key combination like was available in Sublime?
Coming in 1.49 (it is in the Insiders' Build as of this edit) your example will finally work as you expected. See merged pull request.
Vscode will now "remember" your selected text if any, and when you type your snippet prefix, insert it into the TM_SELECTED_TEXT variable even though you seemingly over-typed that selected text.
As of v1.20 this has become easier as a new variable $CLIPBOARD has been added, see new snippet variables. So there is no need to assign and run a shortcut - but you must copy the selection to clipboard CTRL-C.
Your example could now be:
"in quotes": {
"prefix": "inq",
"body": "'$CLIPBOARD:${1:type_here}'"
}
Note: $CLIPBOARD works. There's no need for the extra curly brackets {$CLIPBOARD}.
With the word highlighted, press F1 and run the command "Insert Snippet", then select your snippet on the list.
Also you can edit your keybindings by going to File>Preferences>Keyboard Shortcuts and add some shortcut to the "editor.action.showSnippets" command, like this:
{
"key": "ctrl+alt+s",
"command": "editor.action.showSnippets",
"when": "editorTextFocus"
}
https://github.com/Microsoft/vscode/issues/17780
as per this thread you can assign exact snippet to keybinding by providing args.
keybinding example for bootstrap media queries
{
"key": "ctrl+alt+b",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"name": "bsup"
}
},
{
"key": "ctrl+alt+shift+b",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"name": "bsup_copy"
}
},
snippet example
"bsup": {
"prefix": "bsup",
"body": [
"#include media-breakpoint-up(md){",
"\t${TM_SELECTED_TEXT}",
"}"
],
"description": "Bootstrap media up"
},
"bsup_copy": {
"prefix": "bsup_copy",
"body": [
"${1:${TM_SELECTED_TEXT}}",
"#include media-breakpoint-up(md){",
"\t${2:${TM_SELECTED_TEXT}}",
"}"
],
"description": "Bootstrap media up + copy selected text"
},
UPD: moreover - you can define snippet directly in keybindings.json which seems to be even more convenient for me in some cases
{
"key": "cmd+shift+c",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"snippet": "console.log('${TM_SELECTED_TEXT}', $TM_SELECTED_TEXT$1);"
}
}
using documentation from https://code.visualstudio.com/docs/editor/userdefinedsnippets i was able to customize snippets, i am using 'surround with' extension and can put my own snippet into settings.json as follows:
"html_h3-name": {
"label": "h3",
"description": "wrap by h3 with <a name=''>, top",
"snippet": "<h3><a name=\"${TM_SELECTED_TEXT/[\\s]/-/g}\"></a>$TM_SELECTED_TEXT\n\t<a class=\"small\" href=\"#top\">top</a>\n</h3>"
},
which takes highlighted code in VSCode and creates h3 header from it with a name link:
it converts 'aaa bbb ccc' to
<h3><a name="aaa-bbb-ccc"></a>aaa bbb ccc
<a class="small" href="#top">top</a>
</h3>