2

Context: a question related to building a clickable edit button on any item of a TreeView.

How can I call a callback function when the edit button in front of a TreeViewItem is clicked?

Image of the edit button: https://code.visualstudio.com/api/extension-guides/tree-view#view-actions

I noticed the command property on the TreeItem instance and went through the docs but couldn't understand how to call a callback function with the command.

Any help would be appreciated. Thanks

Docs: https://code.visualstudio.com/docs/extensionAPI/vscode-api#TreeItem

"view/item/context": [
    {
        "command": "issuesList.deleteEntry",
        "when": "view == issuesList && viewItem == dependency",
        "group": "inline"
    },
    {
        "command": "issuesList.viewInVisualizer",
        "when": "view == issuesList && viewItem == dependency"
    }
]
Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
Amir Moghadam
  • 21
  • 1
  • 4

3 Answers3

2

Better later than never :)

Implement Updateable, Interactive vscode.TreeView

  1. Contribute TreeView Update Command
  2. Contribute View Object
  3. Contribute View Update Button
  4. Create & Register the TreeView class
  5. Activate

Contribute TreeView Update Command

Add command contribution to package.json

{
    "contributes": {
        "commands": [
            {
                "command": "Update-TreeView",
                "category": "Custom",
                "title": "Actively updates the tree view",
                "icon": "$(extensions-refresh)"
            }
        ]
    }
}

Contribute View Object

Add view contribution to package.json

{
    "contributes": {
        "views": {
            "explorer": [
                {
                    "id": "customView",
                    "name": "Custom View"
                }
            ]
        }
    }
}

Contribute View Update Button

Add button contribution for customView to package.json. Please note that we assigned the update command we have contribute earlier.

{
    "contributes": {
        "menus": {
            "view/title": [
                {
                    "command": "Update-TreeView",
                    "when": "view == customView",
                    "group": "navigation"
                }
            ]
        }
    }
}

Create & Register the TreeView class

Code Breakdown

  1. refresh - fires when the refresh button is clicked on the view. We achieved that by registering the update command and fire the update event when invoking it.
  2. getChildren - this is the logic by which you will build your tree.
  3. register - a wrapper method for registering the tree provider and the update command.
  4. withProgress - will show a progress bar while your tree is loaded/updated.
  5. TreeItem - a class for creating the tree items.

Important!

Please check the events under register method. They will fire when you perform actions on your tree. In order to get the TreeItem(s) on which the action was preformed, call e.selection or e.element.

Create a new file custom-tree.ts and paste the following code inside

import * as vscode from 'vscode';

export class CustomTreeDataProvider implements vscode.TreeDataProvider<TreeItem> {
    private _onDidChangeTreeData: vscode.EventEmitter<TreeItem | undefined | null | void> = new vscode.EventEmitter<TreeItem | undefined | null | void>();
    readonly onDidChangeTreeData: vscode.Event<TreeItem | undefined | null | void> = this._onDidChangeTreeData.event;

    refresh(): void {
        this._onDidChangeTreeData.fire();
    }

    getTreeItem(element: TreeItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
        return element;
    }

    getChildren(element?: TreeItem | undefined): vscode.ProviderResult<TreeItem[]> {
        return vscode.window.withProgress({ location: { viewId: "customView" } }, () => {
            return new Promise<TreeItem[]>((resolve) => {
                let file = new TreeItem('file.txt', vscode.ThemeIcon.File, undefined);
                let folder = new TreeItem('Parent', vscode.ThemeIcon.Folder, [file]);

                resolve([folder]);
            });
        });
    }

    public register(context: vscode.ExtensionContext): any {
        // setup
        const options = {
            treeDataProvider: this,
            showCollapseAll: true
        };

        // build
        vscode.window.registerTreeDataProvider('customView', this);
        vscode.commands.registerCommand('Update-TreeView', () => {
            this.refresh();
        });

        // create
        const tree = vscode.window.createTreeView('customView', options);
        
        // setup: events
        tree.onDidChangeSelection(e => {
            console.log(e); // breakpoint here for debug
        });
        tree.onDidCollapseElement(e => {
            console.log(e); // breakpoint here for debug
        });
        tree.onDidChangeVisibility(e => {
            console.log(e); // breakpoint here for debug
        });
        tree.onDidExpandElement(e => {
            console.log(e); // breakpoint here for debug
        });

        // subscribe
        context.subscriptions.push(tree);
    }
}

class TreeItem extends vscode.TreeItem {
    children: TreeItem[] | undefined;
    command?: vscode.Command | undefined;

    constructor(
        label: string,
        iconPath?: string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri } | vscode.ThemeIcon,
        children?: TreeItem[] | undefined,
        command?: vscode.Command) {

        super(
            label,
            children === undefined
                ? vscode.TreeItemCollapsibleState.None
                : vscode.TreeItemCollapsibleState.Collapsed);
        this.command = command;
        this.iconPath = iconPath;
        this.children = children;
    }
}

Activate

Add the following code to your activate method under extension.ts.

import * as vscode from 'vscode';
import { CustomTreeDataProvider } from './custom-tree';

export function activate(context: vscode.ExtensionContext) {
  new CustomTreeDataProvider().register(context);
}
Gravity API
  • 680
  • 8
  • 16
1

It seems that you should bind a function to the command by vscode.commands.registerCommand API. The code looks like

import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
    // other code
    vscode.commands.registerCommand('issuesList.deleteEntry', (node: Dependency) => node.deleteEntry());
    vscode.commands.registerCommand('issuesList.viewInVisualizer', (node: Dependency) => viewInVisualizer(node));
}

More detailed usage can be found at https://code.visualstudio.com/api/references/vscode-api#commands, and also a full example of TreeView at https://github.com/microsoft/vscode-extension-samples/tree/master/tree-view-sample

iuyoy
  • 121
  • 1
  • 6
1
    const tree = vscode.window.createTreeView('myview', {treeDataProvider: dataProvider, showCollapseAll: true });
    tree.onDidChangeSelection( e => click(e.selection));
wr_alan
  • 11
  • 1
  • Hi @wr_alan, thank you for answering this question, may I also recommend that providing an explanation can further improve your answer. – Jet Sep 18 '20 at 08:40
  • The question wanted to run a command on the inline icon selection, not the TreeViewItem itself. – Mark Oct 14 '22 at 06:19