提交 5dbfe32b 编写于 作者: A Alex Ross

Allow tree item command to be resolved later

Part of #110498
上级 3a70241a
......@@ -8867,7 +8867,8 @@ declare module 'vscode' {
getParent?(element: T): ProviderResult<T>;
/**
* Called only on hover to resolve the [TreeItem](#TreeItem.tooltip) property if it is undefined.
* Called on hover to resolve the [TreeItem](#TreeItem.tooltip) property if it is undefined.
* Called on tree item click/open to resolve the [TreeItem](#TreeItem.command) property if it is undefined.
* Only properties that were undefined can be resolved in `resolveTreeItem`.
* Functionality may be expanded later to include being called to resolve other missing
* properties on selection and/or on open.
......@@ -8877,7 +8878,7 @@ declare module 'vscode' {
* onDidChangeTreeData should not be triggered from within resolveTreeItem.
*
* *Note* that this function is called when tree items are already showing in the UI.
* Because of that, no property that changes the presentation (label, description, command, etc.)
* Because of that, no property that changes the presentation (label, description, etc.)
* can be changed.
*
* @param element The object associated with the TreeItem
......
......@@ -21,6 +21,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import { MarkdownString } from 'vs/workbench/api/common/extHostTypeConverters';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { Command } from 'vs/editor/common/modes';
type TreeItemHandle = string;
......@@ -184,6 +185,7 @@ interface TreeNode extends IDisposable {
extensionItem: vscode.TreeItem;
parent: TreeNode | Root;
children?: TreeNode[];
disposableStore: DisposableStore;
}
class ExtHostTreeView<T> extends Disposable {
......@@ -379,8 +381,9 @@ class ExtHostTreeView<T> extends Disposable {
const node = this.nodes.get(element);
if (node) {
const resolve = await this.dataProvider.resolveTreeItem(node.extensionItem, element, token) ?? node.extensionItem;
// Resolvable elements. Currently only tooltip.
// Resolvable elements. Currently only tooltip and command.
node.item.tooltip = this.getTooltip(resolve.tooltip);
node.item.command = this.getCommand(node.disposableStore, resolve.command);
return node.item;
}
}
......@@ -573,8 +576,12 @@ class ExtHostTreeView<T> extends Disposable {
return tooltip;
}
private getCommand(disposable: DisposableStore, command?: vscode.Command): Command | undefined {
return command ? this.commands.toInternal(command, disposable) : undefined;
}
private createTreeNode(element: T, extensionTreeItem: vscode.TreeItem, parent: TreeNode | Root): TreeNode {
const disposable = new DisposableStore();
const disposableStore = new DisposableStore();
const handle = this.createHandle(element, extensionTreeItem, parent);
const icon = this.getLightIconPath(extensionTreeItem);
const item: ITreeItem = {
......@@ -584,7 +591,7 @@ class ExtHostTreeView<T> extends Disposable {
description: extensionTreeItem.description,
resourceUri: extensionTreeItem.resourceUri,
tooltip: this.getTooltip(extensionTreeItem.tooltip),
command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command, disposable) : undefined,
command: this.getCommand(disposableStore, extensionTreeItem.command),
contextValue: extensionTreeItem.contextValue,
icon,
iconDark: this.getDarkIconPath(extensionTreeItem) || icon,
......@@ -598,7 +605,8 @@ class ExtHostTreeView<T> extends Disposable {
extensionItem: extensionTreeItem,
parent,
children: undefined,
dispose(): void { disposable.dispose(); }
disposableStore,
dispose(): void { disposableStore.dispose(); }
};
}
......
......@@ -52,7 +52,8 @@ import { IIconLabelMarkdownString } from 'vs/base/browser/ui/iconLabel/iconLabel
import { renderMarkdownAsPlaintext } from 'vs/base/browser/markdownRenderer';
import { API_OPEN_DIFF_EDITOR_COMMAND_ID, API_OPEN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
import { Codicon } from 'vs/base/common/codicons';
import { CancellationToken } from 'vs/base/common/cancellation';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Command } from 'vs/editor/common/modes';
export class TreeViewPane extends ViewPane {
......@@ -535,12 +536,13 @@ export class TreeView extends Disposable implements ITreeView {
}));
this.tree.setInput(this.root).then(() => this.updateContentAreas());
this._register(this.tree.onDidOpen(e => {
this._register(this.tree.onDidOpen(async (e) => {
if (!e.browserEvent) {
return;
}
const selection = this.tree!.getSelection();
const command = selection.length === 1 ? selection[0].command : undefined;
const command = await this.resolveCommand(selection.length === 1 ? selection[0] : undefined);
if (command) {
let args = command.arguments || [];
if (command.id === API_OPEN_EDITOR_COMMAND_ID || command.id === API_OPEN_DIFF_EDITOR_COMMAND_ID) {
......@@ -555,6 +557,17 @@ export class TreeView extends Disposable implements ITreeView {
}
private async resolveCommand(element: ITreeItem | undefined): Promise<Command | undefined> {
let command = element?.command;
if (element && !command) {
if ((element instanceof ResolvableTreeItem) && element.hasResolve) {
await element.resolve(new CancellationTokenSource().token);
command = element.command;
}
}
return command;
}
private onContextMenu(treeMenus: TreeMenus, treeEvent: ITreeContextMenuEvent<ITreeItem>, actionRunner: MultipleSelectionActionRunner): void {
this.hoverService.hideHover();
const node: ITreeItem | null = treeEvent.element;
......
......@@ -704,8 +704,9 @@ export class ResolvableTreeItem implements ITreeItem {
if (resolve && !this.resolved) {
const resolvedItem = await resolve(token);
if (resolvedItem) {
// Resolvable elements. Currently only tooltip.
this.tooltip = resolvedItem.tooltip;
// Resolvable elements. Currently tooltip and command.
this.tooltip = this.tooltip ?? resolvedItem.tooltip;
this.command = this.command ?? resolvedItem.command;
}
}
if (!token.isCancellationRequested) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册