Дублирующая схема просмотра дерева зависит от расширения кода

#typescript #visual-studio-code #vscode-extensions

#typescript #visual-studio-code #vscode-расширения

Вопрос:

Я пишу расширение VS Code, которое реализует пользовательский viewsContainer. Она активируется в onView: событии, указанном в пакете JSON.

Все это отлично работает, и мое представление извлекает данные из статического файла JSON и добавляет каждый узел в представление.

Мой JSON структурирован следующим образом:

 {
  "name": "root",
  "children": {
    "Child1": [
      { "id": "childId1", "name": "childName1" },
      { "id": "childId2", "name": "childId2" }
    ],
    "Child2": [
        { "id": "childId1", "name": "childName1" },
        { "id": "childId2", "name": "childId2" }
    ],
    "Child3": [
        { "id": "childId1", "name": "childName1" },
        { "id": "childId2", "name": "childId2" }
    ],
    "Child4": [
        { "id": "childId1", "name": "childName1" },
        { "id": "childId2", "name": "childId2" }
    ]
  }
}
  

и мой класс, который зарегистрирован как treeviewprovider в extension.ts , является:

 import * as vscode from "vscode";

import * as validateMenuItems from "./validateMenuItems.json";

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

  constructor() {}

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

  getTreeItem(element: ValidateMenu): vscode.TreeItem {
    if(element) {
      console.log(`element: ${element}`);
      return element;
    }

    return element;
  }

  getChildren(element?: ValidateMenu): Thenable<ValidateMenu[]> {
    if (element) {
      return Promise.resolve([]);
    } else {
      return Promise.resolve(this.getValidateMenu());
    }
  }

  private getValidateMenu(): ValidateMenu[] {
    const toMenu = (
      menuTitle: string,
      collapsibleState: vscode.TreeItemCollapsibleState
    ): ValidateMenu => {
      return new ValidateMenu(menuTitle, collapsibleState);
    };

    let menuItems: any = []; 
    let menuHeadings: any = validateMenuItems.children;

    let j: number = 0;
    for (var i in menuHeadings) {
      // send the parent as a menu item
      if (menuHeadings[i] !== null amp;amp; typeof menuHeadings[i] === "object") {
        let firstChildLabel: string = Object.keys(validateMenuItems.children)[
          j
        ];
        let parentMenuItem = toMenu(
          firstChildLabel,
          vscode.TreeItemCollapsibleState.Collapsed 
        );
        menuItems.push(parentMenuItem);

        // send each child object to the view
        for (var k = 0; k < menuHeadings[i].length; k  ) {
          if (
            menuHeadings[i][k] !== null amp;amp;
            typeof menuHeadings[i][k] === "object"
          ) {
            let secondChildLabel: string = menuHeadings[i][k].name;
            let childMenuItem = toMenu(
              secondChildLabel,
              vscode.TreeItemCollapsibleState.None
            );
            menuItems.push(childMenuItem);
          } else {
            return [];
          }
        }
      } else {
        return [];
      }
      j  ;
    }

    return menuItems;
  }
}

export class ValidateMenu extends vscode.TreeItem {
  constructor(
    public readonly label: string,
    public readonly collapsibleState: vscode.TreeItemCollapsibleState,
    public readonly command?: vscode.Command
  ) {
    super(label, collapsibleState);
  }
}
  

Что это делает, так это помещает каждый элемент в JSON в представление, первый набор объектов под root.children как свернутые элементы, а их соответствующие дочерние элементы как нерасширяемые / сворачиваемые.

Однако для каждого из расширяемых элементов, если я нажимаю, чтобы развернуть его, вся остальная часть схемы JSON повторяется под ним.

Из пошагового просмотра кадров стека вызовов выясняется, что требуемый getChildren() метод сначала вызывается при регистрации поставщика и при каждом событии расширения.

Мой вопрос в том, что, поскольку getChildren() требуется <Thenable> , где я ошибаюсь в своей реализации с getValidateMenu() , которая позволит избежать дублирования схемы на свернутых объектах и фактически сгруппировать дочерние объекты внутри свернутого элемента?

Должны ли непосредственные root.children элементы иметь команду, которая вызывает какой-то onclick метод, который получает this и раскрывает свои дочерние элементы?

Любые указатели от тех, кто более знаком, с благодарностью.

Ответ №1:

Вы не getChildren() правильно реализуете. Это задокументировано следующим образом:

Получите дочерние элементы element или root, если ни один элемент не передан.

Вместо этого ваша реализация, похоже, делает «возвращает плоский список всех элементов дерева, когда не element передается, и пустой список в противном случае».

Вам нужно фактически вернуть дочерние элементы запрошенного element (и только непосредственные дочерние элементы, вместо того, чтобы возвращать все дерево сразу для корневого элемента).

Возможно, стоит ознакомиться с официальным образцом просмотра дерева.

Комментарии:

1. Спасибо @Gama11 Я знал, что моя реализация была неправильной, просто не был уверен в источнике проблемы. Я работал с образцом представления дерева MS из GitHub, и следование их подходу было тем, что меня смутило. Спасибо за вашу помощь!

2. Вероятно, самым простым подходом было бы добавить children поле в ваш TreeItem подкласс и таким образом сделать структуру данных рекурсивной. Затем вы можете просто вернуться element.children в getChildren() .

3. @Gamma11 Я понимаю, что вы говорите, но я продолжаю сталкиваться с проблемами с ‘ Promise<ValidateMenu[]> is not assignable to type ValidateMenu , даже если я добавляю необязательное children поле. Вы предлагаете изменить реализацию getValidateMenu() метода и просто вернуть ValidateMenu объект в качестве разрешенного обещания? Проверка типа действительно расстраивает, когда я оборачиваюсь

4. Честно говоря, я бы, вероятно, просто вернул данные напрямую, вместо того чтобы возиться с promises и Thenables, поскольку кажется, что у вас уже есть все данные на момент getChildren() выполнения вызова в любом случае. Обратите внимание, что возвращаемый тип — это ProivderResult , который может быть Thenable или необработанными данными. code.visualstudio.com/api/references/vscode-api#ProviderResult

5. Хорошо, спасибо за вашу помощь. Я попытаюсь разобраться в этом и опубликовать отредактированный ответ, как только перестану биться головой о свой стол

Ответ №2:

Даже я довольно долго боролся с этим, нашел репозиторий github, общий для OP, в другом вопросе. Я думаю, что стоит упомянуть об этом здесь, чтобы другие получили выгоду.

https://github.com/trebleCode/dxdevcheck/blob/master/src/validateMenu.ts

Ключевым моментом для меня было добавить children поле в мой TreeItem подкласс, как упоминалось @Gama11 в комментариях.

Комментарии:

1. так много этого! Спасибо, что добавили мою ссылку на репозиторий