#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#ProviderResult5. Хорошо, спасибо за вашу помощь. Я попытаюсь разобраться в этом и опубликовать отредактированный ответ, как только перестану биться головой о свой стол
Ответ №2:
Даже я довольно долго боролся с этим, нашел репозиторий github, общий для OP, в другом вопросе. Я думаю, что стоит упомянуть об этом здесь, чтобы другие получили выгоду.
https://github.com/trebleCode/dxdevcheck/blob/master/src/validateMenu.ts
Ключевым моментом для меня было добавить children
поле в мой TreeItem
подкласс, как упоминалось @Gama11 в комментариях.
Комментарии:
1. так много этого! Спасибо, что добавили мою ссылку на репозиторий