提交 23fe7a39 编写于 作者: M Matt Bierner

Split extHost webview panels to own file

上级 72cbf699
......@@ -78,6 +78,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { ExtHostWebviewViews } from 'vs/workbench/api/common/extHostWebviewView';
import { ExtHostCustomEditors } from 'vs/workbench/api/common/extHostCustomEditors';
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
......@@ -144,8 +145,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation));
rpcProtocol.set(ExtHostContext.ExtHostWebviewPanels, extHostWebviews);
const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews));
const extHostWebviewPanels = rpcProtocol.set(ExtHostContext.ExtHostWebviewPanels, new ExtHostWebviewPanels(rpcProtocol, extHostWebviews, extHostWorkspace));
const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews, extHostWebviewPanels));
const extHostWebviewViews = rpcProtocol.set(ExtHostContext.ExtHostWebviewViews, new ExtHostWebviewViews(rpcProtocol, extHostWebviews));
// Check that no named customers are missing
......@@ -569,7 +570,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostOutputService.createOutputChannel(name);
},
createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options?: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel {
return extHostWebviews.createWebviewPanel(extension, viewType, title, showOptions, options);
return extHostWebviewPanels.createWebviewPanel(extension, viewType, title, showOptions, options);
},
createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options?: vscode.WebviewOptions): vscode.WebviewEditorInset {
checkProposedApiEnabled(extension);
......@@ -594,7 +595,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostTreeViews.createTreeView(viewId, options, extension);
},
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer);
return extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializer);
},
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider | vscode.CustomReadonlyEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
return extHostCustomEditors.registerCustomEditorProvider(extension, viewType, provider, options);
......
......@@ -14,6 +14,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import type * as vscode from 'vscode';
import { Cache } from './cache';
......@@ -165,6 +166,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
private readonly _extHostDocuments: ExtHostDocuments,
private readonly _extensionStoragePaths: IExtensionStoragePaths | undefined,
private readonly _extHostWebview: ExtHostWebviews,
private readonly _extHostWebviewPanels: ExtHostWebviewPanels,
) {
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadCustomEditors);
}
......@@ -260,7 +262,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
}
const webview = this._extHostWebview.createNewWebview(handle, options, entry.extension);
const panel = this._extHostWebview.createNewWebviewPanel(handle, viewType, title, position, options, webview);
const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, title, position, options, webview);
const revivedResource = URI.revive(resource);
......@@ -297,7 +299,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
throw new Error(`Provider does not implement move '${viewType}'`);
}
const webview = this._extHostWebview.getWebviewPanel(handle);
const webview = this._extHostWebviewPanels.getWebviewPanel(handle);
if (!webview) {
throw new Error(`No webview found`);
}
......
......@@ -4,20 +4,15 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as modes from 'vs/editor/common/modes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import type * as vscode from 'vscode';
import * as extHostProtocol from './extHost.protocol';
import * as extHostTypes from './extHostTypes';
export class ExtHostWebview implements vscode.Webview {
......@@ -116,169 +111,11 @@ export class ExtHostWebview implements vscode.Webview {
}
}
type IconPath = URI | { light: URI, dark: URI };
export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
class ExtHostWebviewPanel extends Disposable implements vscode.WebviewPanel {
readonly #handle: extHostProtocol.WebviewHandle;
readonly #proxy: extHostProtocol.MainThreadWebviewPanelsShape;
readonly #viewType: string;
readonly #webview: ExtHostWebview;
readonly #options: vscode.WebviewPanelOptions;
#title: string;
#iconPath?: IconPath;
#viewColumn: vscode.ViewColumn | undefined = undefined;
#visible: boolean = true;
#active: boolean = true;
#isDisposed: boolean = false;
readonly #onDidDispose = this._register(new Emitter<void>());
public readonly onDidDispose = this.#onDidDispose.event;
readonly #onDidChangeViewState = this._register(new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
public readonly onDidChangeViewState = this.#onDidChangeViewState.event;
constructor(
handle: extHostProtocol.WebviewHandle,
proxy: extHostProtocol.MainThreadWebviewPanelsShape,
viewType: string,
title: string,
viewColumn: vscode.ViewColumn | undefined,
editorOptions: vscode.WebviewPanelOptions,
webview: ExtHostWebview
) {
super();
this.#handle = handle;
this.#proxy = proxy;
this.#viewType = viewType;
this.#options = editorOptions;
this.#viewColumn = viewColumn;
this.#title = title;
this.#webview = webview;
}
public dispose() {
if (this.#isDisposed) {
return;
}
this.#isDisposed = true;
this.#onDidDispose.fire();
this.#proxy.$disposeWebview(this.#handle);
this.#webview.dispose();
super.dispose();
}
get webview() {
this.assertNotDisposed();
return this.#webview;
}
get viewType(): string {
this.assertNotDisposed();
return this.#viewType;
}
get title(): string {
this.assertNotDisposed();
return this.#title;
}
set title(value: string) {
this.assertNotDisposed();
if (this.#title !== value) {
this.#title = value;
this.#proxy.$setTitle(this.#handle, value);
}
}
get iconPath(): IconPath | undefined {
this.assertNotDisposed();
return this.#iconPath;
}
set iconPath(value: IconPath | undefined) {
this.assertNotDisposed();
if (this.#iconPath !== value) {
this.#iconPath = value;
this.#proxy.$setIconPath(this.#handle, URI.isUri(value) ? { light: value, dark: value } : value);
}
}
get options() {
return this.#options;
}
get viewColumn(): vscode.ViewColumn | undefined {
this.assertNotDisposed();
if (typeof this.#viewColumn === 'number' && this.#viewColumn < 0) {
// We are using a symbolic view column
// Return undefined instead to indicate that the real view column is currently unknown but will be resolved.
return undefined;
}
return this.#viewColumn;
}
public get active(): boolean {
this.assertNotDisposed();
return this.#active;
}
public get visible(): boolean {
this.assertNotDisposed();
return this.#visible;
}
_updateViewState(newState: { active: boolean; visible: boolean; viewColumn: vscode.ViewColumn; }) {
if (this.#isDisposed) {
return;
}
if (this.active !== newState.active || this.visible !== newState.visible || this.viewColumn !== newState.viewColumn) {
this.#active = newState.active;
this.#visible = newState.visible;
this.#viewColumn = newState.viewColumn;
this.#onDidChangeViewState.fire({ webviewPanel: this });
}
}
public reveal(viewColumn?: vscode.ViewColumn, preserveFocus?: boolean): void {
this.assertNotDisposed();
this.#proxy.$reveal(this.#handle, {
viewColumn: viewColumn ? typeConverters.ViewColumn.from(viewColumn) : undefined,
preserveFocus: !!preserveFocus
});
}
private assertNotDisposed() {
if (this.#isDisposed) {
throw new Error('Webview is disposed');
}
}
}
export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape, extHostProtocol.ExtHostWebviewPanelsShape {
private static newHandle(): extHostProtocol.WebviewHandle {
return generateUuid();
}
private readonly _proxy: extHostProtocol.MainThreadWebviewPanelsShape;
private readonly _webviewProxy: extHostProtocol.MainThreadWebviewsShape;
private readonly _webviews = new Map<extHostProtocol.WebviewHandle, ExtHostWebview>();
private readonly _webviewPanels = new Map<extHostProtocol.WebviewHandle, ExtHostWebviewPanel>();
private readonly _serializers = new Map<string, {
readonly serializer: vscode.WebviewPanelSerializer;
readonly extension: IExtensionDescription;
}>();
constructor(
mainContext: extHostProtocol.IMainContext,
......@@ -287,32 +124,9 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape, ex
private readonly _logService: ILogService,
private readonly _deprecationService: IExtHostApiDeprecationService,
) {
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviewPanels);
this._webviewProxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
}
public createWebviewPanel(
extension: IExtensionDescription,
viewType: string,
title: string,
showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean },
options: (vscode.WebviewPanelOptions & vscode.WebviewOptions) = {},
): vscode.WebviewPanel {
const viewColumn = typeof showOptions === 'object' ? showOptions.viewColumn : showOptions;
const webviewShowOptions = {
viewColumn: typeConverters.ViewColumn.from(viewColumn),
preserveFocus: typeof showOptions === 'object' && !!showOptions.preserveFocus
};
const handle = ExtHostWebviews.newHandle();
this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options));
const webview = this.createNewWebview(handle, options, extension);
const panel = this.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview);
return panel;
}
public $onMessage(
handle: extHostProtocol.WebviewHandle,
message: any
......@@ -330,91 +144,6 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape, ex
this._logService.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`);
}
public $onDidChangeWebviewPanelViewStates(newStates: extHostProtocol.WebviewPanelViewStateData): void {
const handles = Object.keys(newStates);
// Notify webviews of state changes in the following order:
// - Non-visible
// - Visible
// - Active
handles.sort((a, b) => {
const stateA = newStates[a];
const stateB = newStates[b];
if (stateA.active) {
return 1;
}
if (stateB.active) {
return -1;
}
return (+stateA.visible) - (+stateB.visible);
});
for (const handle of handles) {
const panel = this.getWebviewPanel(handle);
if (!panel) {
continue;
}
const newState = newStates[handle];
panel._updateViewState({
active: newState.active,
visible: newState.visible,
viewColumn: typeConverters.ViewColumn.to(newState.position),
});
}
}
async $onDidDisposeWebviewPanel(handle: extHostProtocol.WebviewHandle): Promise<void> {
const panel = this.getWebviewPanel(handle);
panel?.dispose();
this._webviewPanels.delete(handle);
this._webviews.delete(handle);
}
public registerWebviewPanelSerializer(
extension: IExtensionDescription,
viewType: string,
serializer: vscode.WebviewPanelSerializer
): vscode.Disposable {
if (this._serializers.has(viewType)) {
throw new Error(`Serializer for '${viewType}' already registered`);
}
this._serializers.set(viewType, { serializer, extension });
this._proxy.$registerSerializer(viewType);
return new extHostTypes.Disposable(() => {
this._serializers.delete(viewType);
this._proxy.$unregisterSerializer(viewType);
});
}
async $deserializeWebviewPanel(
webviewHandle: extHostProtocol.WebviewHandle,
viewType: string,
title: string,
state: any,
position: EditorViewColumn,
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
): Promise<void> {
const entry = this._serializers.get(viewType);
if (!entry) {
throw new Error(`No serializer found for '${viewType}'`);
}
const { serializer, extension } = entry;
const webview = this.createNewWebview(webviewHandle, options, extension);
const revivedPanel = this.createNewWebviewPanel(webviewHandle, viewType, title, position, options, webview);
await serializer.deserializeWebviewPanel(revivedPanel, state);
}
public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: number, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, webview: ExtHostWebview) {
const panel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
this._webviewPanels.set(webviewHandle, panel);
return panel;
}
public createNewWebview(handle: string, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, extension: IExtensionDescription): ExtHostWebview {
const webview = new ExtHostWebview(handle, this._webviewProxy, reviveOptions(options), this.initData, this.workspace, extension, this._deprecationService);
this._webviews.set(handle, webview);
......@@ -424,12 +153,12 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape, ex
return webview;
}
private getWebview(handle: extHostProtocol.WebviewHandle): ExtHostWebview | undefined {
return this._webviews.get(handle);
public deleteWebview(handle: string) {
this._webviews.delete(handle);
}
public getWebviewPanel(handle: extHostProtocol.WebviewHandle): ExtHostWebviewPanel | undefined {
return this._webviewPanels.get(handle);
private getWebview(handle: extHostProtocol.WebviewHandle): ExtHostWebview | undefined {
return this._webviews.get(handle);
}
}
......@@ -437,7 +166,7 @@ export function toExtensionData(extension: IExtensionDescription): extHostProtoc
return { id: extension.identifier, location: extension.extensionLocation };
}
function convertWebviewOptions(
export function convertWebviewOptions(
extension: IExtensionDescription,
workspace: IExtHostWorkspace | undefined,
options: vscode.WebviewPanelOptions & vscode.WebviewOptions,
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as modes from 'vs/editor/common/modes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { convertWebviewOptions, ExtHostWebview, ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import type * as vscode from 'vscode';
import * as extHostProtocol from './extHost.protocol';
import * as extHostTypes from './extHostTypes';
type IconPath = URI | { light: URI, dark: URI };
class ExtHostWebviewPanel extends Disposable implements vscode.WebviewPanel {
readonly #handle: extHostProtocol.WebviewHandle;
readonly #proxy: extHostProtocol.MainThreadWebviewPanelsShape;
readonly #viewType: string;
readonly #webview: ExtHostWebview;
readonly #options: vscode.WebviewPanelOptions;
#title: string;
#iconPath?: IconPath;
#viewColumn: vscode.ViewColumn | undefined = undefined;
#visible: boolean = true;
#active: boolean = true;
#isDisposed: boolean = false;
readonly #onDidDispose = this._register(new Emitter<void>());
public readonly onDidDispose = this.#onDidDispose.event;
readonly #onDidChangeViewState = this._register(new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
public readonly onDidChangeViewState = this.#onDidChangeViewState.event;
constructor(
handle: extHostProtocol.WebviewHandle,
proxy: extHostProtocol.MainThreadWebviewPanelsShape,
viewType: string,
title: string,
viewColumn: vscode.ViewColumn | undefined,
editorOptions: vscode.WebviewPanelOptions,
webview: ExtHostWebview
) {
super();
this.#handle = handle;
this.#proxy = proxy;
this.#viewType = viewType;
this.#options = editorOptions;
this.#viewColumn = viewColumn;
this.#title = title;
this.#webview = webview;
}
public dispose() {
if (this.#isDisposed) {
return;
}
this.#isDisposed = true;
this.#onDidDispose.fire();
this.#proxy.$disposeWebview(this.#handle);
this.#webview.dispose();
super.dispose();
}
get webview() {
this.assertNotDisposed();
return this.#webview;
}
get viewType(): string {
this.assertNotDisposed();
return this.#viewType;
}
get title(): string {
this.assertNotDisposed();
return this.#title;
}
set title(value: string) {
this.assertNotDisposed();
if (this.#title !== value) {
this.#title = value;
this.#proxy.$setTitle(this.#handle, value);
}
}
get iconPath(): IconPath | undefined {
this.assertNotDisposed();
return this.#iconPath;
}
set iconPath(value: IconPath | undefined) {
this.assertNotDisposed();
if (this.#iconPath !== value) {
this.#iconPath = value;
this.#proxy.$setIconPath(this.#handle, URI.isUri(value) ? { light: value, dark: value } : value);
}
}
get options() {
return this.#options;
}
get viewColumn(): vscode.ViewColumn | undefined {
this.assertNotDisposed();
if (typeof this.#viewColumn === 'number' && this.#viewColumn < 0) {
// We are using a symbolic view column
// Return undefined instead to indicate that the real view column is currently unknown but will be resolved.
return undefined;
}
return this.#viewColumn;
}
public get active(): boolean {
this.assertNotDisposed();
return this.#active;
}
public get visible(): boolean {
this.assertNotDisposed();
return this.#visible;
}
_updateViewState(newState: { active: boolean; visible: boolean; viewColumn: vscode.ViewColumn; }) {
if (this.#isDisposed) {
return;
}
if (this.active !== newState.active || this.visible !== newState.visible || this.viewColumn !== newState.viewColumn) {
this.#active = newState.active;
this.#visible = newState.visible;
this.#viewColumn = newState.viewColumn;
this.#onDidChangeViewState.fire({ webviewPanel: this });
}
}
public reveal(viewColumn?: vscode.ViewColumn, preserveFocus?: boolean): void {
this.assertNotDisposed();
this.#proxy.$reveal(this.#handle, {
viewColumn: viewColumn ? typeConverters.ViewColumn.from(viewColumn) : undefined,
preserveFocus: !!preserveFocus
});
}
private assertNotDisposed() {
if (this.#isDisposed) {
throw new Error('Webview is disposed');
}
}
}
export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanelsShape {
private static newHandle(): extHostProtocol.WebviewHandle {
return generateUuid();
}
private readonly _proxy: extHostProtocol.MainThreadWebviewPanelsShape;
private readonly _webviewPanels = new Map<extHostProtocol.WebviewHandle, ExtHostWebviewPanel>();
private readonly _serializers = new Map<string, {
readonly serializer: vscode.WebviewPanelSerializer;
readonly extension: IExtensionDescription;
}>();
constructor(
mainContext: extHostProtocol.IMainContext,
private readonly webviews: ExtHostWebviews,
private readonly workspace: IExtHostWorkspace | undefined,
) {
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviewPanels);
}
public createWebviewPanel(
extension: IExtensionDescription,
viewType: string,
title: string,
showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean },
options: (vscode.WebviewPanelOptions & vscode.WebviewOptions) = {},
): vscode.WebviewPanel {
const viewColumn = typeof showOptions === 'object' ? showOptions.viewColumn : showOptions;
const webviewShowOptions = {
viewColumn: typeConverters.ViewColumn.from(viewColumn),
preserveFocus: typeof showOptions === 'object' && !!showOptions.preserveFocus
};
const handle = ExtHostWebviewPanels.newHandle();
this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options));
const webview = this.webviews.createNewWebview(handle, options, extension);
const panel = this.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview);
return panel;
}
public $onDidChangeWebviewPanelViewStates(newStates: extHostProtocol.WebviewPanelViewStateData): void {
const handles = Object.keys(newStates);
// Notify webviews of state changes in the following order:
// - Non-visible
// - Visible
// - Active
handles.sort((a, b) => {
const stateA = newStates[a];
const stateB = newStates[b];
if (stateA.active) {
return 1;
}
if (stateB.active) {
return -1;
}
return (+stateA.visible) - (+stateB.visible);
});
for (const handle of handles) {
const panel = this.getWebviewPanel(handle);
if (!panel) {
continue;
}
const newState = newStates[handle];
panel._updateViewState({
active: newState.active,
visible: newState.visible,
viewColumn: typeConverters.ViewColumn.to(newState.position),
});
}
}
async $onDidDisposeWebviewPanel(handle: extHostProtocol.WebviewHandle): Promise<void> {
const panel = this.getWebviewPanel(handle);
panel?.dispose();
this._webviewPanels.delete(handle);
this.webviews.deleteWebview(handle);
}
public registerWebviewPanelSerializer(
extension: IExtensionDescription,
viewType: string,
serializer: vscode.WebviewPanelSerializer
): vscode.Disposable {
if (this._serializers.has(viewType)) {
throw new Error(`Serializer for '${viewType}' already registered`);
}
this._serializers.set(viewType, { serializer, extension });
this._proxy.$registerSerializer(viewType);
return new extHostTypes.Disposable(() => {
this._serializers.delete(viewType);
this._proxy.$unregisterSerializer(viewType);
});
}
async $deserializeWebviewPanel(
webviewHandle: extHostProtocol.WebviewHandle,
viewType: string,
title: string,
state: any,
position: EditorViewColumn,
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
): Promise<void> {
const entry = this._serializers.get(viewType);
if (!entry) {
throw new Error(`No serializer found for '${viewType}'`);
}
const { serializer, extension } = entry;
const webview = this.webviews.createNewWebview(webviewHandle, options, extension);
const revivedPanel = this.createNewWebviewPanel(webviewHandle, viewType, title, position, options, webview);
await serializer.deserializeWebviewPanel(revivedPanel, state);
}
public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: number, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, webview: ExtHostWebview) {
const panel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
this._webviewPanels.set(webviewHandle, panel);
return panel;
}
public getWebviewPanel(handle: extHostProtocol.WebviewHandle): ExtHostWebviewPanel | undefined {
return this._webviewPanels.get(handle);
}
}
......@@ -13,6 +13,7 @@ import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { NullApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import type * as vscode from 'vscode';
import { SingleProxyRPCProtocol } from './testRPCProtocol';
......@@ -35,6 +36,8 @@ suite('ExtHostWebview', () => {
isExtensionDevelopmentDebug: false,
}, undefined, new NullLogService(), NullApiDeprecationService);
const extHostWebviewPanels = new ExtHostWebviewPanels(rpcProtocol!, extHostWebviews, undefined);
let lastInvokedDeserializer: vscode.WebviewPanelSerializer | undefined = undefined;
class NoopSerializer implements vscode.WebviewPanelSerializer {
......@@ -48,20 +51,20 @@ suite('ExtHostWebview', () => {
const serializerA = new NoopSerializer();
const serializerB = new NoopSerializer();
const serializerARegistration = extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializerA);
const serializerARegistration = extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerA);
await extHostWebviews.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {});
await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {});
assert.strictEqual(lastInvokedDeserializer, serializerA);
assert.throws(
() => extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializerB),
() => extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB),
'Should throw when registering two serializers for the same view');
serializerARegistration.dispose();
extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializerB);
extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB);
await extHostWebviews.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {});
await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {});
assert.strictEqual(lastInvokedDeserializer, serializerB);
});
......@@ -71,7 +74,10 @@ suite('ExtHostWebview', () => {
webviewResourceRoot: 'vscode-resource://{{resource}}',
isExtensionDevelopmentDebug: false,
}, undefined, new NullLogService(), NullApiDeprecationService);
const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {});
const extHostWebviewPanels = new ExtHostWebviewPanels(rpcProtocol!, extHostWebviews, undefined);
const webview = extHostWebviewPanels.createWebviewPanel({} as any, 'type', 'title', 1, {});
assert.strictEqual(
webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html')).toString(),
......@@ -110,7 +116,10 @@ suite('ExtHostWebview', () => {
webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit/{{resource}}`,
isExtensionDevelopmentDebug: false,
}, undefined, new NullLogService(), NullApiDeprecationService);
const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {});
const extHostWebviewPanels = new ExtHostWebviewPanels(rpcProtocol!, extHostWebviews, undefined);
const webview = extHostWebviewPanels.createWebviewPanel({} as any, 'type', 'title', 1, {});
function stripEndpointUuid(input: string) {
return input.replace(/^https:\/\/[^\.]+?\./, '');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册