On property change event handler - visual-studio-code

In a VSCode extension I'm looking for a way to react when the user modify an extension property defined in contributes.configuration section of package.json.
Does it exists an event like onPropertyChange or some other way to register an event handler?

After re-reading vscode documentation I found myself an answer:
workspace.onDidChangeConfiguration callback receive a ConfigurationChangeEvent when a config property is modified.
with the method affectsConfiguration it is then possible to react at the specific property change, for example:
export function activate(context: vscode.ExtensionContext) {
vscode.workspace.onDidChangeConfiguration(event => {
let affected = event.affectsConfiguration("riot.compiler");
if (affected) {
// rebuild cpp project settings
setup();
}
})
...

Related

how to add and select color for nodes/tree view items in explorer view in my vscode extension

I have added my own explorer view in my extension.
Here I added nodes/tree view items however I am not finding any way to customize and choose color my tree view items in explorer view.
Any idea how to achieve this?
There should be some way because when some file has error then its color is set to different compared to other open file.
[I assume this is your github issue: Not able to use FileDecorationProvider for tree view item.]
Here is my attempt at using a FileDecorationProvider for a custom TreeView. With the caveat that I am new to typescript and FileDecorations.
If you have seen Support proposed DecorationProvider api on custom views you know there are limitations on using a FileDecorationProvider for coloring TreeItem's - primarily that the decoration/coloration cannot be limited to your treeView - wherever that resourceUri apeears, like in the Explorer, your fileDecoration will be applied. That is very unfortunate but I don't believe there is any way to avoid that for now.
First, in your TreeItem class you will have to give whichever items you want decorated a resourceUri. Like this:
export class TreeTab extends vscode.TreeItem {
constructor( public readonly tab: vscode.Tab, public index: number = 0 ) {
super(tab.label, vscode.TreeItemCollapsibleState.None);
this.tab = tab;
if (tab.input instanceof vscode.TabInputText) {
this.resourceUri = tab.input.uri;
}
}
Ignore the specifics of the code for my extension, the point is:
this.resourceUri = <some vscode.Uri>;
Secondly, this is how I set up my FileDecoration class:
import {window, Tab, TabInputText, Uri, Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, ThemeColor} from 'vscode';
export class TreeFileDecorationProvider implements FileDecorationProvider {
private disposables: Array<Disposable> = [];
private readonly _onDidChangeFileDecorations: EventEmitter<Uri | Uri[]> = new EventEmitter< Uri | Uri[]>();
readonly onDidChangeFileDecorations: Event<Uri | Uri[]> = this._onDidChangeFileDecorations.event;
constructor() {
this.disposables = [];
this.disposables.push(window.registerFileDecorationProvider(this));
}
async updateActiveEditor(activeTab: Tab): Promise<void> {
if (activeTab.input instanceof TabInputText)
this._onDidChangeFileDecorations.fire(activeTab.input.uri);
// filter to get only non-activeTabs
activeTab.group.tabs.map( tab => {
if (!tab.isActive && tab.input instanceof TabInputText)
this._onDidChangeFileDecorations.fire(tab.input.uri);
});
}
async provideFileDecoration(uri: Uri): Promise<FileDecoration | undefined> {
const activeEditor = window.activeTextEditor.document.uri;
if (uri.fsPath === activeEditor.fsPath) {
return {
badge: "⇐",
color: new ThemeColor("charts.red"),
// color: new vscode.ThemeColor("tab.activeBackground"),
// tooltip: ""
};
}
else return null; // to get rid of the custom fileDecoration
}
dispose() {
this.disposables.forEach((d) => d.dispose());
}
}
provideFileDecoration(uri: Uri) does the actual decorating. It finds only certain files and decorates them, and by returning null resets that previously decorated uri (as supplied by the uri argument).
updateActiveEditor() is an exported method that I call in other parts of the extension when I want to change a file decoration. So elsewhere I have this in another file:
import { TreeFileDecorationProvider } from './fileDecorator';
export class EditorManager {
public TreeItemDecorator: TreeFileDecorationProvider;
// and then on a listener that gets triggered when I need to make a change to some things including the FileDecoration for a uri
this.TreeItemDecorator.updateActiveEditor(activeTab);
this.TreeItemDecorator.updateActiveEditor(activeTab); that calls the updateActiveEditor method in the TreeFileDecorationProvider class which calls the this._onDidChangeFileDecorations.fire(<some uri>); method for uri's that need to have the decoration applied and also for uri's that need to have the decoration removed.
this._onDidChangeFileDecorations.fire(<some uri>); will call provideFileDecoration(uri: Uri) where the actual decoration will be applied or removed depending on some state of that uri.
I am sure there is a way to call onDidChangeFileDecorations() directly from another file in your project (if you don't need to do any pre-processing of the uri like I have to do. I just haven't figured out how to construct the argument for that function yet. Perhaps someone will help on that point.
You can see here:
color: new ThemeColor("charts.red"),
// color: new vscode.ThemeColor("tab.activeBackground"),
how a color is chosen - it must be some ThemeColor. The charts theme colors has a few basic colors that are handy to refer to. See theme color references, Charts therein.
The badge option can take up to 2 characters, but as you see I copied/pasted a unicode character for mine and that works.
As I mentioned my FileDecorationProvider is called from an eventListener, but you may not need that for your use case - if decorations do not have to added and removed based on user actions like in my case. So you may be able to call your FileDecorationProvider right from your extension.ts activate() like so:
import * as vscode from 'vscode';
import { TreeFileDecorationProvider } from './fileDecorator';
export async function activate(context: vscode.ExtensionContext) {
new TreeFileDecorationProvider();
}
Other references:
a treeDecorationProvider.ts example
part of the git extension that does file decorations
Custom view decorations in VSCode extension

How to know what suggestion item is selected in vscode

I complete a vscode extension by vscode.languages.registerCompletionItemProvider(selector, new FuncCompletionProvider(),'.')
I want to listen which suggestion is selected. In the image below,when I click the current item I want to get the CompletionItem Info.
I tried to use the resolveCompletionItem function, but before the suggestion is selected resolveCompletionItem was triggered.
I tried to use the resolveCompletionItem function, but before the suggestion is selected resolveCompletionItem was triggered.
It appears this is intentional. Per their docs:
Note that this function is called when completion items are already showing in the UI or when an item has been selected for insertion
'selected' meaning selected in the list, not committed
The recommended way to gain insight on when a CompletionItem is inserted is using the CompletionProvider#command property:
An optional command that is executed after inserting this completion. Note that additional modifications to the current document should be described with the additionalTextEdits-property.
Example usage:
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider('html', new MyCompletionProvider),
vscode.commands.registerCommand("doTheThing", () => {
console.log('did the thing!!');
});
);
}
class MyCompletionProvider implements vscode.CompletionItemProvider {
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
const myHTMLCompletionItem: vscode.CompletionItem = new vscode.CompletionItem("myHTML");
myHTMLCompletionItem.command = {
title: '',
command: 'doTheThing'
};
return new vscode.CompletionList([myHTMLCompletionItem]);
}
}

Events provider is deprecating. Using Redux or Observables for state in ionic apps

I've been using events in my ionic application, where i subscribe in one page, and publish the event in the other page. Now I see a warning that Events are going to be changed with Observables and Redux state and effect.
I was using Events mainly to call for component function changes outside it, so I had a components for example:
Component1.ts
this.events.subscribe('event:addValue1', (data: any) => {
this.valueName = 'VALUE1';
});
this.events.subscribe('event:addValue2', (data: any) => {
this.valueName = 'VALUE2';
});
and than outside this component I was calling the publish methods from any page, like:
Page1.ts
this.events.publish('event:addValue1');
Page2.ts
this.events.publish('event:addValue2');
By this i was able to change the data (this.valueName) outside the Component1.ts from any other page, simply by publishing the desired event.
I know that this might not sound or be right approach, but It was the only way I was doing changes to my Component1.ts outside it from any page.
I have now changed this and just put separate functions and than i access them via ViewChild component name like
#ViewChild('component') component: any;
....
this.component.functionAddValue1().
and additionally I send additional params via Angular NavigationExtras if i need to calculate and call some function from the Component1.ts, lets say if I navigate to some route.
Before this I was just calling the events.publish and I was able to make the changes to the Component1.ts on the fly.
Create event service.
In the EventService.ts:
export class EventService {
private dataObserved = new BehaviorSubject<any>('');
currentEvent = this.dataObserved.asObservable();
constructo(){}
publish(param):void {
this.dataObserved.next(param);
}
}
For publishing the event from example page1:
constructor(public eventService:EventService){}
updatePost(value){
this.eventService.publish({name:'post:updated',params:value});
}
In page 2:
constructor(public eventService:EventService){
eventService.currentEvent.subscribe(value=>{
if(value.name=='post:updated'){
//get value.name
}else if(value.name=='another:event'){
//get value or update view or trigger function or method...
}
// here you can get the value or do whatever you want
});
}

VSCode API - 'textInputFocus' for webview or custom undo handling

I am working on VSCode extension implementation.
I am using webview for my extension - in result there is something similar to visual editor, when you can select items and edit.
In result I want to implement custom undo/redo handling for webview.
I have following code to handle VSCode's 'undo'/'redo' commands:
let undoCommand: Disposable;
let redoCommand: Disposable;
const registerCommands = () => {
undoCommand = commands.registerCommand('undo', async (args) => {
// Call custom undo handler
triggerCustomUndo(appJsonFilePath, extensionWebView.webview);
// Execute default undo handler
return commands.executeCommand('default:undo', args);
});
redoCommand = commands.registerCommand('redo', async (args) => {
// Call custom redo handler
triggerCustomRedo(appJsonFilePath, extensionWebView.webview);
// Execute default redo handler
return commands.executeCommand('default:redo', args);
});
};
extensionWebView.onDidChangeViewState((action: WebviewPanelOnDidChangeViewStateEvent) => {
if (!action.webviewPanel.visible || !action.webviewPanel.active) {
undoCommand.dispose();
redoCommand.dispose();
} else {
registerCommands();
}
});
registerCommands();
It works for me.
In result my custom undo/redo handler is called when I select 'undo'/'redo' from VSCode's menu:
Problem is that when I am using 'Ctrl+Z'|'Command+Z' shortcut, then 'undo' command is not called for webview.
This happens because of following 'when' clause in default keybindings:
If I remove 'textInputFocus' statement from 'when' clause, then 'undo' command is called for webview when keyboard shortcut is used.
Some information regarding 'when' contexts - https://github.com/microsoft/vscode-docs/blob/master/docs/getstarted/keybindings.md#contexts
Question:
Is there a way how I can set 'textInputFocus' to 'true', when I am using webview?
Alternative way could be:
I can read keybinding attachments
Default - 'vscode://defaultsettings/keybindings.json'
Custom/Overwritten:
Windows - %APPDATA%\Code\User\keybindings.json;
MacOS - $HOME/Library/Application Support/Code/User/keybindings.json;
Linux - $HOME/.config/Code/User/keybindings.json;
Attach to keyboard key down event manually and handle event to detect 'undo'/'redo' key combination;
That should work, but if I could somehow set 'textInputFocus' to 'true' for webview then it would be much easier.
Or maybe there is other simpler solution available?
I found way how to set 'textInputFocus' manually:
vscode.commands.executeCommand('setContext', 'textInputFocus', true);

Possible to show users of your VSCode extension / color theme notifications on update?

Is it possible to show users of your extension or color theme notifications in Visual Studio Code? For someone who has my color theme or extension installed and is getting updates, I would like to possibly show this person a notification after they update the extension (That could be on launch of VSCode, or right after they go into the market to update & reload the extension and client themselves.)
For example: I think it would be beneficial to me and not invasive if they saw a notification after updating the extension saying "Feedback? Suggestions? Fixes?..on the theme?" OR notifying them of something changed in the theme that may not be favorable. So they can "opt out" of that change if they want (Like an extra set of borders around something or the color change of something.)
Obviously people with all notifications off would not be affected, but I thought an occasional notification after a rare update wouldn't be too bad. I have not been able to find info on if this is possible, and if it was, how to do it. Any info on this is appreciated. And if it is possible, those reading this, whether you've done it or not, would you recommend showing a notification to your theme users in that way?
Thanks :)
Show a notification on bottom-right corner, whenever your extension is updated. You can also control to show it only for major/minor releases.
That's how it looks:
Add below code to extension.ts:
import { window, ExtensionContext, extensions, env, Uri } from "vscode";
const extensionId = "jerrygoyal.shortcut-menu-bar";
// this method is called when your extension is activated
export function activate(context: ExtensionContext) {
showWhatsNew(context); // show notification in case of a major release i.e. 1.0.0 -> 2.0.0
}
// https://stackoverflow.com/a/66303259/3073272
function isMajorUpdate(previousVersion: string, currentVersion: string) {
// rain-check for malformed string
if (previousVersion.indexOf(".") === -1) {
return true;
}
//returns int array [1,1,1] i.e. [major,minor,patch]
var previousVerArr = previousVersion.split(".").map(Number);
var currentVerArr = currentVersion.split(".").map(Number);
if (currentVerArr[0] > previousVerArr[0]) {
return true;
} else {
return false;
}
}
async function showWhatsNew(context: ExtensionContext) {
const previousVersion = context.globalState.get<string>(extensionId);
const currentVersion = extensions.getExtension(extensionId)!.packageJSON
.version;
// store latest version
context.globalState.update(extensionId, currentVersion);
if (
previousVersion === undefined ||
isMajorUpdate(previousVersion, currentVersion)
) {
// show whats new notificatin:
const actions = [{ title: "See how" }];
const result = await window.showInformationMessage(
`Shortcut Menubar v${currentVersion} — Add your own buttons!`,
...actions
);
if (result !== null) {
if (result === actions[0]) {
await env.openExternal(
Uri.parse(
"https://github.com/GorvGoyl/Shortcut-Menu-Bar-VSCode-Extension#create-buttons-with-custom-commands"
)
);
}
}
}
}
You can see this implementation in my VSCode extension repo Shortcut Menu Bar
I think you can register the version during activation event and check for it on each activation. Then you can do whatever you want. For instance GitLens is migrating settings https://github.com/eamodio/vscode-gitlens/blob/master/src/extension.ts#L52 and i'm pretty sure I remember that they were opening a notification (but i have not found immediately in the code)
regards,