vscode enable/disable命令在自定义树视图中,基于节点/item的属性
我目前正在研究一种自定义VSCODE扩展程序,该扩展是从远程API获取数据并在自定义树视图中提供数据。 TreeView本身允许基于某些预定义的标准(例如搜索词)与API和IE过滤器结果进行交互。
出于简单原因,我创建了一个自己的 github project 只是专注于基本的设置和配置在某些假API方法上或多或少可运行但提供类似典型的CRUD API提供的树木。
gif进行了调整以适合2MB限制,因此
在treeview上显示命令时 会产生丑陋的文物 由自定义
treedataprovider
和treeitem
定义的代码>,通过定义以下内容
...
{
"contributes":
"commands": [
{
"command": "extension.myTreeView.filter",
"title": "Filter",
"icon": "$(filter)",
"when": "view == extension.myTreeView"
},
{
"command": "extension.myTreeView.resetFilter",
"title": "Reset Filter",
"shortTitle": "Reset",
"icon": "$(close)",
"enablement": "view == extension.myTreeView && extension.myTreeView.hasFilter",
"when": "view == extension.myTreeView && extension.myTreeView.hasFilter"
},
{
"command": "extension.myTreeView.delete",
"title": "Delete Item",
"shortTitle": "Delete",
"icon": "$(trash)",
"when": "view == extension.myTreeView && viewItem == archive"
}
...
],
"menus": {
"view/title": [
{
"command": "extension.myTreeView.filter",
"when": "view == extension.myTreeView"
"group": "navigation@1"
},
{
"command": "extension.myTreeView.resetFilter",
"when": "view == extension.myTreeView",
"group": "navigation@2"
},
...
],
"view/item/context": [
...
{
"command": "extension.myTreeView.delete",
"when": "view == extension.myTreeView && viewItem == archive",
"group": "inline@3"
}
]
}
},
...
:我以某种方式努力为针对特定项目本身的命令添加有利条件。即,树允许下载该节点表示的项目(或附加到)中包含的某些文件。这样的节点可能会或可能没有附带的文件,因此启用下载操作仅对于至少有文件可以下载的节点才有意义。虽然通常下载该内容或渲染以触发下载操作的按钮并不是问题,但该命令的启用选项是我有点不知情的地方。
我通过定义了此类树节点的不同种类的contextValue
来暂时“解决”该问题,一个用于存档,一个没有文件可以下载。尽管总体上似乎解决了这个问题,但它a)不合适,b)导致下游问题。想象一下,可以将档案锁定,以防止不属于该组的用户存档被锁定以进行实际下载。这只是一个虚构的情况,但应该说明您可能最终会结合该contextValue
变量中的属性字段的组合,您或多或少需要在该启用语句中解析。每个可能的上下文值选项必须通过整个命令
和菜单
类似的定义来携带:
...
{
"command": "extension.myTreeView.delete",
"when": "view == extension.myTreeView && viewItem == archive || viewItem == archiveWithFiles || viewItem == ...",
"group": "inline@2"
},
...
通常.com/api/references/wher-clause-contexts#add-a-custom-当custom-当c-custom-custem-pherause-context“ rel =“ nofollow noreferrer”>自定义上下文变量,例如hasfilter
在上面显示的示例命令配置中,可以在enablement
和中使用
等级时,可用于显示/hide或hide或启用/禁用某些命令,但是这些似乎是仅在整棵树本身,而不在特定的树项目上工作。 IE示例应用程序使用以下代码来启用/禁用resetFilter
命令,该命令是基于是否定义的:
...
public async updateFilter(filter: Filter): Promise<void> {
this.filter = filter;
await commands.executeCommand("setContext", TestTreeDataProvider.CONTEXT_HAS_FILTER, true);
this.items = [];
this._onDidChangeTreeData.fire();
}
private async resetFilter(): Promise<void> {
this.filter = undefined;
await commands.executeCommand("setContext", TestTreeDataProvider.CONTEXT_HAS_FILTER, false);
this.items = [];
this._onDidChangeTreeData.fire();
}
这起作用,因为这或多或少是对树本身的全局操作,并且具有一个它反应的单一财产来源。但是,此类上下文值可能只有分配给它们的基本类型或仅在条款中检查其可用性的键(又称属性名称)的对象。我可能会创建每个树生成的树项目的自定义上下文变量,但是我需要某种形式的解决机制,因为每个上下文值名称必须不同,否则它们被下一个节点的上下文值所覆盖。而且,由于树可以容纳大量节点,因此我觉得每个节点上的上下文值也不是很表现的。最后,这里似乎缺少的是一种将函数定义为上下文值的方法,该函数允许当前节点(TreeItem或该节点所引用的实际对象)为输入,并且需要将基本类型之一返回为输出,即true
或false
确定是否应启用该项目。
我觉得在此问题上必须有一个更容易的解决方案,这就是为什么我在这里问。简而言之,如何基于当前树项目的上下文(由属性或该节点上执行的函数)在Visual Studio代码中启用/禁用命令?
I'm currently working on a custom VSCode extension that fetches data from a remote API and presents the data within a custom tree-view. The treeview itself allows to interact with the API and i.e. filter results based on some predefined criteria such as a search term or whether or not the response has some files attached to it, adding new nodes to or removing or updating existing nodes in the tree dynamically.
For simplicity reasons I created an own Github project to just focus on the basic setup and configuration of a tree that more or less operates on some fake API methods but provides similar capabilities typical CRUD APIs provide.
GIF was resized to fit the 2MB limit and thus produces ugly artifacts
While showing action-icons for commands on a TreeView
, defined by a custom TreeDataProvider
, and on a TreeItem
are fairly straight forward by defining something like:
...
{
"contributes":
"commands": [
{
"command": "extension.myTreeView.filter",
"title": "Filter",
"icon": "$(filter)",
"when": "view == extension.myTreeView"
},
{
"command": "extension.myTreeView.resetFilter",
"title": "Reset Filter",
"shortTitle": "Reset",
"icon": "$(close)",
"enablement": "view == extension.myTreeView && extension.myTreeView.hasFilter",
"when": "view == extension.myTreeView && extension.myTreeView.hasFilter"
},
{
"command": "extension.myTreeView.delete",
"title": "Delete Item",
"shortTitle": "Delete",
"icon": "$(trash)",
"when": "view == extension.myTreeView && viewItem == archive"
}
...
],
"menus": {
"view/title": [
{
"command": "extension.myTreeView.filter",
"when": "view == extension.myTreeView"
"group": "navigation@1"
},
{
"command": "extension.myTreeView.resetFilter",
"when": "view == extension.myTreeView",
"group": "navigation@2"
},
...
],
"view/item/context": [
...
{
"command": "extension.myTreeView.delete",
"when": "view == extension.myTreeView && viewItem == archive",
"group": "inline@3"
}
]
}
},
...
in the package.json
file, I somehow struggle to add enabling conditions to commands targeting a particular item itself. I.e. the tree allows the download of some files contained in (or attached to) the item represented by the node. Such nodes may or may not have files attached to them and thus enabling the download action only makes sense for nodes that at least have a file to download. While generally downloading that content or rendering the button for triggering the download action isn't the issue, the enabling option for that command is where I am a bit clueless.
I temporarily "solved" that issue by defining different kinds of contextValue
's for such tree nodes, one for an archive with and one without files to download. While this in general seems to solve that issue, it a) doesn't feel proper and b) leads to downstream problems. Imagine that archives can be locked preventing users who do not belong to the group the archive was locked for the actual download. This is just a fictional case here but should illustrate that you might end up with a combination of property fields within that contextValue
variable that you more or less need to parse in that enable statement. And each further possible context value option must be carried around through the whole commands
and menus
definitions like this:
...
{
"command": "extension.myTreeView.delete",
"when": "view == extension.myTreeView && viewItem == archive || viewItem == archiveWithFiles || viewItem == ...",
"group": "inline@2"
},
...
In general, custom context variables, such as hasFilter
in the sample command configuration shown above, which can be used in the enablement
and when
clauses, can be used to show/hide or enable/disable certain commands but these seem to work only on the whole tree itself and not a particular tree item. I.e. the sample application uses the following code to enable/disable the resetFilter
command based on whether a filter is defined or not:
...
public async updateFilter(filter: Filter): Promise<void> {
this.filter = filter;
await commands.executeCommand("setContext", TestTreeDataProvider.CONTEXT_HAS_FILTER, true);
this.items = [];
this._onDidChangeTreeData.fire();
}
private async resetFilter(): Promise<void> {
this.filter = undefined;
await commands.executeCommand("setContext", TestTreeDataProvider.CONTEXT_HAS_FILTER, false);
this.items = [];
this._onDidChangeTreeData.fire();
}
This works as this is more or less a global action on the tree itself and has a single source of property it reacts to. But such context values may only have base types assigned to them or objects where only the keys (a.k.a. property names) of that objects are checked for their availability in in
clauses. I could potentially create custom context variables per tree item generated but then I need some form of addressing mechanism as each of the context value names must be different or else they are overwritten by the context value of the next node. And as the tree can hold plenty of nodes I feel adding a context value per node is also not very performant then. In the end what seems to be missing here is a way to define a function as context value that allows the current node (either the TreeItem or the actual object the node is referring to) as input and needs to return one of the base types as output, i.e. true
or false
to determine whether that item should be enabled or not.
While this SO question here may sound similar, it actually asks for disabling the whole tree item node when I just want the command that can be performed on that tree item to enable/disabled based on some tree item's current property value. Some styling of TreeItem
s based on their context can be done via FileDecorationProvider
's. That question also is a result of a bug inside VSCode that doesn't seem to force a rerender on any changes done to the enablement guards.
I feel that there must be an easier solution on this matter and that's why I ask here. In short, how can a command be enabled/disabled in Visual Studio Code based on the current tree items' context (either properties held by or functions executed on that node)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
现在,您将类型描述作为TreeItem的上下文值。
为什么不将允许的操作也放在上下文值中:
然后在子句时在
中使用它
You now put a type description as the context value of the TreeItem.
Why not put the allowed operations also in the context value:
Then use this in the
when
clause