我正在构建一个可以创建多个 webview 的 VS Code 扩展;每个文本编辑器文档都可以有一个关联的 webview。我希望用户能够在 web 视图中右键单击并执行命令。该命令必须知道在其中单击了哪个 webview 实例才能做正确的事。
上下文菜单回调仅接收
{webview:<viewType>}
作为参数。如果有帮助,以下是简化的扩展代码,显示我如何为每个
document.uri
创建一个新的 webview(和关联的查看器管理器):
import * as vscode from 'vscode';
import {commands, TextEditor, window} from 'vscode';
import {Viewer} from './viewer';
export function activate(ctx: vscode.ExtensionContext) {
let manager = new MyExtManager();
const subs = ctx.subscriptions;
subs.push(commands.registerCommand('myExt.show', () => {
manager.showWebview(ctx.extensionUri);
}));
subs.push(commands.registerCommand('myExt.myCtxItem', (wv) => {
// need some unique identifier here to locate original editor
console.log(wv);
}));
}
class MyExtManager {
private viewerByDoc: Map<vscode.Uri, Viewer> = new Map();
public showWebview(extensionURI: vscode.Uri) {
const editor: TextEditor | undefined = window.activeTextEditor;
const doc = editor?.document;
if (doc && doc.languageId === "xml") {
let viewerForDoc = this.viewerByDoc.get(doc.uri);
if (viewerForDoc) {
viewerForDoc.reveal();
} else {
const panel = vscode.window.createWebviewPanel(
'myxmlviewer', `My Viewer for ${doc.uri}`,
vscode.ViewColumn.Beside
);
panel.onDidDispose(() => this.viewerByDoc.delete(doc.uri));
viewerForDoc = new Viewer(editor, panel)
this.viewerByDoc.set(doc.uri, viewerForDoc);
}
}
}
}
我调查过的事情:
vscode.window.active*
,因为没有像 activeTextEditor
那样查看活动网络视图的集合。我能想到的唯一技巧是劫持
viewType
参数,使其对每个查看器实例都是唯一的。我找不到太多关于此参数的意图,但具有唯一值似乎是一种意外使用。
上下文菜单是通过
package.json
文件中的这些添加内容构建的:
{
"contributes": {
"commands": [
{
"category": "XML Viewer",
"command": "myExt.show",
"title": "Open to the Side"
},
{
"category": "XML Viewer",
"command": "myExt.myCtxItem",
"title": "Do a Thing Here"
},
],
"menus": {
"webview/context": [
{
"command": "myExt.myCtxItem",
"group": "xmlViewer"
}
]
}
}
}
想出办法:
创建WebviewPanel时,注册一个
onDidChangeViewState
回调。检查面板是否处于活动和可见状态,如果是,则用它覆盖单个变量。
public activeWebview: WebviewPanel | null = null;
// ...
panel.onDidChangeViewState(e => {
if (panel.active && panel.visible) {
this.activeWebview = panel;
} else if (activeWebview===panel) {
this.activeWebview = null;
}
});
...然后在扩展的命令注册中使用它:
subs.push(commands.registerCommand('myExt.myCtxItem', () => {
if (manager.activeWebview) {
// ...
}
}));
我实际上做的工作比上面的多得多,因此如果与 webview 关联的
TextEditor
可用,命令仍然可用……但这超出了这个问题的范围。