VS Code - Getting currently selected TreeItem

时间:2019-04-16 23:06:08

标签: typescript visual-studio-code vscode-extensions

In my TypeScript extension, I have a custom view that lists all of the JSON files available inside of workspaceRoot/Data

What I'd like to do is run the toggleSelectedIcon() method I have on a type extending TreeItem. Problem so far is I'm not sure how to properly do this after I've initially built my view.

My class file

import * as vscode from "vscode";
import * as path from "path";
import * as fs from "fs";

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

  private _workspaceRoot;
  private _workspaceFolders;
  private _dataFolder;

  constructor() {
    this._workspaceRoot = vscode.workspace.rootPath;
    this._workspaceFolders = fs.readdirSync(this._workspaceRoot);
    let workspaceFolders: Array<string> = this._workspaceFolders;
    // check if there is a Data folder or not
    for (let folder in workspaceFolders) {
      if (workspaceFolders[folder] === "Data") {
        // check that the finding is a directory
        let checkIsDirectory = fs
          .statSync(`${this._workspaceRoot}\\Data`)
          .isDirectory();
        if (checkIsDirectory === true) {
          this._dataFolder = `${this._workspaceRoot}\\Data`;
        } else {
          vscode.window.showErrorMessage(
            "Workspace root does not contain a folder named 'Data'"
          );
        }
      }
    }
  }

  toggleChild() {
  }

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

  getTreeItem(element?: DataMenu): vscode.TreeItem {
    return element;
  }

  getChildren(element?: DataMenu): DataMenu[] {
    if (element) {
      return element.children;
    } else {
      let jsonChildren = this.getJSONFiles(this._dataFolder);
      let listParent = new DataMenu(
        "Objects",
        vscode.TreeItemCollapsibleState.Expanded,
        this._workspaceRoot,
        null,
        null,
        []
      );
      let dataMenu = this.createDataMenu(listParent, jsonChildren);
      return [dataMenu];
    }
  }

  createDataMenu(parent: DataMenu, children: any[]) {
    let menuChildren: DataMenu[] = [];
    let myCommand: vscode.Command = {command: 'dataMenu.toggleSelection', title: 'Toggle Selection', };
    // create jsonChildren from getChildren as DataMenu objects
    for (let item in children) {
      let childMenuItem = new DataMenu(
        children[item],
        vscode.TreeItemCollapsibleState.None,
        vscode.Uri.file(`${this._workspaceRoot}\\${children[item]}`),
        vscode.FileType.File,
        false,
        null,
        myCommand,
        {
          light: path.join(
            __filename,
            "..",
            "..",
            "resources",
            "light",
            "check-empty.svg"
          ),
          dark: path.join(
            __filename,
            "..",
            "..",
            "resources",
            "dark",
            "check-empty.svg"
          )
        }
      );
      menuChildren.push(childMenuItem);
    }
    parent.children = menuChildren;
    return parent;
  }

  getJSONFiles(source: fs.PathLike) {
    let children = fs.readdirSync(source, "utf-8");
    let extensionType = ".json";
    let targetChildren = [];

    for (let child in children) {
      if (typeof children[child] === "string") {
        let currentChild = children[child].toString();
        if (path.extname(currentChild).toLowerCase() === extensionType) {
          targetChildren.push(currentChild);
        }
      }
    }

    if (targetChildren.length > 0) {
      return targetChildren;
    } else {
      return null;
    }
  }

  normalizeNFC(items: string): string;
  normalizeNFC(items: string[]): string[];
  normalizeNFC(items: string | string[]): string | string[] {
    if (process.platform !== "darwin") {
      return items;
    }

    if (Array.isArray(items)) {
      return items.map(item => item.normalize("NFC"));
    }

    return items.normalize("NFC");
  }
}

export class FileStat implements vscode.FileStat {
  constructor(private fsStat: fs.Stats) {}

  get type(): vscode.FileType {
    return this.fsStat.isFile()
      ? vscode.FileType.File
      : this.fsStat.isDirectory()
      ? vscode.FileType.Directory
      : this.fsStat.isSymbolicLink()
      ? vscode.FileType.SymbolicLink
      : vscode.FileType.Unknown;
  }

  get isFile(): boolean | undefined {
    return this.fsStat.isFile();
  }

  get isDirectory(): boolean | undefined {
    return this.fsStat.isDirectory();
  }

  get isSymbolicLink(): boolean | undefined {
    return this.fsStat.isSymbolicLink();
  }

  get size(): number {
    return this.fsStat.size;
  }

  get ctime(): number {
    return this.fsStat.ctime.getTime();
  }

  get mtime(): number {
    return this.fsStat.mtime.getTime();
  }
}

export class DataMenu extends vscode.TreeItem {
  constructor(
    public readonly label: string,
    public readonly collapsibleState: vscode.TreeItemCollapsibleState,
    public uri: vscode.Uri,
    public type?: vscode.FileType,
    public isSelected?: boolean,
    public children?: DataMenu[],
    public readonly command?: vscode.Command,
    public iconPath?
  ) {
    super(label, collapsibleState);
  }

  toggleSelectedIcon(): void {
    let newLightUncheckedIcon: any;
    let newDarkUncheckedIcon: any;
    let newLightCheckedIcon: any;
    let newDarkCheckedIcon: any;

    newLightUncheckedIcon = path.join(
      __filename,
      "..",
      "..",
      "resources",
      "light",
      "check-empty.svg"
    );
    newDarkUncheckedIcon = path.join(
      __filename,
      "..",
      "..",
      "resources",
      "dark",
      "check-empty.svg"
    );

    newLightCheckedIcon = path.join(
      __filename,
      "..",
      "..",
      "resources",
      "light",
      "check.svg"
    );
    newDarkCheckedIcon = path.join(
      __filename,
      "..",
      "..",
      "resources",
      "dark",
      "check.svg"
    );

    if (this.iconPath === undefined) {
      this.iconPath = {
        light: newLightUncheckedIcon,
        dark: newDarkUncheckedIcon
      };
      this.isSelected = false;
    } else if (
      this.iconPath.light === newLightUncheckedIcon ||
      this.iconPath.dark === newDarkUncheckedIcon
    ) {
      this.iconPath = { light: newLightCheckedIcon, dark: newDarkCheckedIcon };
      this.isSelected = true;
    } else if (
      this.iconPath.light === newLightCheckedIcon ||
      this.iconPath.dark === newDarkCheckedIcon
    ) {
      this.iconPath = {
        light: newLightUncheckedIcon,
        dark: newDarkUncheckedIcon
      };
      this.isSelected = false;
    }
  }
}

The commands section of my package.json

"commands": [
            {
                "command": "validateMenu.refreshList",
                "title": "Validate My System",
                "icon": {
                    "light": "resources/light/refresh.svg",
                    "dark": "resources/dark/refresh.svg"
                }
            },
            {
                "command": "showValidateReport",
                "title": "Show Validation Report",
                "icon": {
                    "light": "resources/light/menu.svg",
                    "dark": "resources/light/menu.svg"
                }
            },
            {
                "command": "dataMenu.refreshFile",
                "title": "Refresh File",
                "icon": {
                    "light": "resources/light/refresh.svg",
                    "dark": "resources/dark/refresh.svg"
                }
            },
            {
                "command": "dataMenu.toggleSelection",
                "title": "Add file to sync",
                "icon": {
                    "light": "resources/light/check-empty.svg",
                    "dark": "resources/dark/check-empty.svg"
                }
            },
            {
                "command": "dataMenu.refreshList",
                "title": "Refresh List",
                "icon": {
                    "light": "resources/light/refresh.svg",
                    "dark": "resources/dark/refresh.svg"
                }
            }
        ],

Using this inside of the DataMenuProvider doesn't offer me a way to get the TreeItem I clicked on in the UI, so I'm not able to use it as an index to target a specific DataMenu object and run its toggleSelectedIcon() method.

My extension.ts file:

import * as vscode from 'vscode';
import { DataMenuProvider } from './dataMenu';

export async function activate(context: vscode.ExtensionContext) {

    const dataMenuProvider = new DataMenuProvider();
    vscode.window.registerTreeDataProvider('dataMenu', dataMenuProvider);
    vscode.commands.registerCommand('dataMenu.refreshList', () => dataMenuProvider.refresh());
    vscode.commands.registerCommand('dataMenu.toggleSelection', () => dataMenuProvider.toggleChild());
}

export function deactivate() {}

How could I map a command I contribute to each DataMenu object? Or other approach?

Any help appreciated!

0 个答案:

没有答案