How to prevent commands from being displayed if the extension is not active? - visual-studio-code

I am writing an extension and I'm providing a custom command, declare in the package.json as:
{
"contributes": {
"commands": [
{
"command": "myext.doSomething",
"title": "Do something"
}
]
}
}
I'm am then registering it in the extension, when it activates:
commands.registerCommand("myext.doSomething", () => console.log("hi"))
This works, but the Do Something command is present in the command palette even if the extension is not active.
This means that if the user selects the command when the extension is not active, an error along the lines of
command myext.doSomething not found
Is there a way to prevent custom commands to be displayed in the command palette unless the extension has been activated?

Instead of not showing your command when the extension is not active, you can just add it to the activationEvents like this in your package.json. In your case:
{
"activationEvents": [
"onCommand:myext.doSomething"
]
}
This will run the exported activate function of your extension before the command is invoked.
Also the when keyword could be an option for you. I answered a similar question on that topic here.
Edit:
You can control a command's visibility in the command pallette by additionally contributing a contextual menu (docs). Then you can for instance only display the command when the editor's file has a specific language id.
Example:
{
"menus": {
"commandPalette": [
{
"command": "myext.doSomething",
"when": "editorLangId==scala"
}
]
}
}

Related

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.

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"});
``

Custom button is not showing in the VS code editor title menu bar

In an extension I want to add a button to display in the VS code editor title menu bar when it opens a synapse XML document.In order to that, I added the following command in commands of package.json file,
{
"command": "webview.show",
"title": "Show Diagram",
"category": "Webview",
"icon": {
"light": "./resources/images/icons/design-view.svg",
"dark": "./resources/images/icons/design-view-inverse.svg"
}
}
and in the package.json file I added the following editor/title,
"menus": {
"editor/title": [
{
"when": "resourceLangId == SynapseXml",
"command": "webview.show",
"group": "navigation"
}
],
}
But when I run the extension and opens a synapse XML document, it will not showing the button in the editor title menu bar.
Further I followed following documentation also,
https://code.visualstudio.com/api/references/contribution-points#contributes.menus
How can I display the button in VS code editor title menu bar?
I added your command and menu entry to an extension I'm making and the button appears where it should (all be it without an image in my screenshot as I don't have the icon). In my screenshot it is the empty space on the left of the ying-yang button - the tooltip is visible though on mouse over. I just removed the "where" test so I would guess that resourceLangId is not what you think it is or maybe the icons path is wrong so it looks like it isn't there as in my screenshot
For anyone still having the same issue:
In my case, using the correct context name field (editorLangId) to match the language ID in the when clause of the command fixed the issue.
https://code.visualstudio.com/api/references/when-clause-contexts#available-contexts
"menus": {
"editor/title": [
{
"when": "editorLangId == SynapseXml",
"command": "webview.show",
"group": "navigation"
}
]
}

How do I contribute a command to the VS Code explorer title bar or command palette that is only active when my webview is focused?

I'm writing an extension that uses VS Code's webview api. My extension also registers a refresh preview command that updates the webview's content. How can I make it so that:
The refresh preview command only shows up in the command palette when my webview is focused?
The refresh preview command shows in the webview's editor title bar?
First, create a custom context key that tracks when your webview is focused. Use VS Code's setContext command to make this context key track when your webview is focused:
const myWebview = ...;
// Make the context key track when one of your webviews is focused
myWebview.onDidChangeViewState(({ webviewPanel }) => {
vscode.commands.executeCommand('setContext',
'myWebviewFocused',
webviewPanel.active);
});
Then use your context key in the when clauses of your extension's menus contribution point
For a command with the id myExtension.refreshPreview, to ensure that command only shows up in the command palette when your webview is focused, use the following contribution:
{
"contributes": {
"menus": {
"commandPalette": [
{
"command": "myExtension.refreshPreview",
"when": "myWebviewFocused",
}
]
}
}
}
For adding a command (possible with icon) to the editor title bar of your webview, use the editor/title contribution point:
{
"contributes": {
"menus": {
"editor/title": [
{
"command": "myExtension.refreshPreview",
"when": "myWebviewFocused",
}
]
}
}
}
Check out VS Code's built-in markdown extension for a more advanced example of this.

Sublime Text Select and Copy in one (macro and keybinding) not working, why?

I have a select-copy.sublime-macro files that contains this:
[
{ "command": "expand_selection_to_word" },
{ "command": "copy" }
]
I then have this in my sublime-keymap file:
{
"keys": ["ctrl+d"],
"command": "run_macro_file",
"args": {"file": "Packages/User/select-copy.sublime-macro" }
}
However, given a line like this:
property: val[|]ue;
Where [|] is the cursor, when I press my keybinding (ctrl+d), I would expect to get 'value' copied. However, when I paste, I actually get the whole line (property: value).
Any idea why?
That happens because expand_selection_to_word its not a command (the right command its expand_selection, and 'words' should be the value of the 'to' argument).
So, change your macro to this and it should work:
[
{
"command": "expand_selection",
"args": {"to": "word"}
},
{
"command": "copy"
}
]
Note: the macro was selecting the whole line because its the default behavior of the copy command if nothing its selected (you can try using ctrl+c when nothing its selected). In addition, if you open the console and execute the macro you should see a warning message saying Unknown macro command expand_selection_to_word.