From ea5f05a43584dad12808a974cddbc3ab0368ff4e Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Fri, 5 Mar 2021 18:49:04 -0800 Subject: [PATCH] Trying to clairify how webview options are used and passed around - Move protocol types into protocol - Hold off on combining the options objects until serialization - Add explicit converstions instead of using `...` - Make a few methods take property bags to help avoid passing arguments in wrong order --- src/vs/editor/common/modes.ts | 27 -------- .../webview/common/webviewPortMapping.ts | 4 +- .../api/browser/mainThreadCodeInsets.ts | 31 ++++----- .../api/browser/mainThreadCustomEditors.ts | 13 ++-- .../api/browser/mainThreadWebviewPanels.ts | 30 ++++++--- .../api/browser/mainThreadWebviews.ts | 17 +++-- .../workbench/api/common/extHost.protocol.ts | 64 ++++++++++++++++--- .../api/common/extHostCustomEditors.ts | 12 ++-- src/vs/workbench/api/common/extHostWebview.ts | 23 +++---- .../api/common/extHostWebviewPanels.ts | 39 +++++++---- .../browser/customEditorInputFactory.ts | 26 +++++--- .../update/browser/releaseNotesEditor.ts | 2 + .../webview/browser/baseWebviewElement.ts | 5 +- .../contrib/webview/browser/webview.ts | 16 ++++- .../electron-sandbox/resourceLoading.ts | 6 +- .../browser/webviewEditorInputFactory.ts | 23 +++++-- .../browser/webviewWorkbenchService.ts | 46 +++---------- .../test/browser/api/extHostWebview.test.ts | 14 +++- 18 files changed, 228 insertions(+), 170 deletions(-) diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 75c3b055ca7..d912576a766 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1683,33 +1683,6 @@ export interface CommentThreadChangedEvent { readonly changed: CommentThread[]; } -/** - * @internal - */ -export interface IWebviewPortMapping { - webviewPort: number; - extensionHostPort: number; -} - -/** - * @internal - */ -export interface IWebviewOptions { - readonly enableScripts?: boolean; - readonly enableCommandUris?: boolean; - readonly localResourceRoots?: ReadonlyArray; - readonly portMapping?: ReadonlyArray; -} - -/** - * @internal - */ -export interface IWebviewPanelOptions { - readonly enableFindWidget?: boolean; - readonly retainContextWhenHidden?: boolean; -} - - export interface CodeLens { range: IRange; id?: string; diff --git a/src/vs/platform/webview/common/webviewPortMapping.ts b/src/vs/platform/webview/common/webviewPortMapping.ts index 4e9c229762f..5f7fafd3371 100644 --- a/src/vs/platform/webview/common/webviewPortMapping.ts +++ b/src/vs/platform/webview/common/webviewPortMapping.ts @@ -10,8 +10,8 @@ import { IAddress } from 'vs/platform/remote/common/remoteAgentConnection'; import { extractLocalHostUriMetaDataForPortMapping, ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; export interface IWebviewPortMapping { - webviewPort: number; - extensionHostPort: number; + readonly webviewPort: number; + readonly extensionHostPort: number; } /** diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts index 1256682d49e..140fa60e9d4 100644 --- a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts +++ b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts @@ -3,16 +3,16 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { UriComponents, URI } from 'vs/base/common/uri'; -import * as modes from 'vs/editor/common/modes'; -import { MainContext, MainThreadEditorInsetsShape, IExtHostContext, ExtHostEditorInsetsShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; -import { extHostNamedCustomer } from '../common/extHostCustomers'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { isEqual } from 'vs/base/common/resources'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { reviveWebviewContentOptions } from 'vs/workbench/api/browser/mainThreadWebviews'; +import { ExtHostContext, ExtHostEditorInsetsShape, IExtHostContext, IWebviewOptions, MainContext, MainThreadEditorInsetsShape } from 'vs/workbench/api/common/extHost.protocol'; +import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; +import { extHostNamedCustomer } from '../common/extHostCustomers'; // todo@jrieken move these things back into something like contrib/insets class EditorWebviewZone implements IViewZone { @@ -70,7 +70,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { this._disposables.dispose(); } - async $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise { + async $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise { let editor: IActiveCodeEditor | undefined; id = id.substr(0, id.indexOf(',')); //todo@jrieken HACK @@ -91,10 +91,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { const webview = this._webviewService.createWebviewElement('' + handle, { enableFindWidget: false, - }, { - allowScripts: options.enableScripts, - localResourceRoots: options.localResourceRoots ? options.localResourceRoots.map(uri => URI.revive(uri)) : undefined - }, { id: extensionId, location: URI.revive(extensionLocation) }); + }, reviveWebviewContentOptions(options), { id: extensionId, location: URI.revive(extensionLocation) }); const webviewZone = new EditorWebviewZone(editor, line, height, webview); @@ -117,7 +114,6 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { const inset = this.getInset(handle); this._insets.delete(handle); inset.dispose(); - } $setHtml(handle: number, value: string): void { @@ -125,12 +121,9 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { inset.webview.html = value; } - $setOptions(handle: number, options: modes.IWebviewOptions): void { + $setOptions(handle: number, options: IWebviewOptions): void { const inset = this.getInset(handle); - inset.webview.contentOptions = { - ...options, - localResourceRoots: options.localResourceRoots?.map(components => URI.from(components)), - }; + inset.webview.contentOptions = reviveWebviewContentOptions(options); } async $postMessage(handle: number, value: any): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts index 2489c0b5bc8..6d5acfdc01d 100644 --- a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts @@ -13,7 +13,6 @@ import { Schemas } from 'vs/base/common/network'; import { basename } from 'vs/base/common/path'; import { isEqual, isEqualOrParent, toLocalResource } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; -import * as modes from 'vs/editor/common/modes'; import { localize } from 'vs/nls'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { FileChangesEvent, FileChangeType, FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; @@ -99,11 +98,11 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc this._editorProviders.clear(); } - public $registerTextEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, capabilities: extHostProtocol.CustomTextEditorCapabilities): void { + public $registerTextEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: extHostProtocol.IWebviewPanelOptions, capabilities: extHostProtocol.CustomTextEditorCapabilities): void { this.registerEditorProvider(CustomEditorModelType.Text, reviveWebviewExtension(extensionData), viewType, options, capabilities, true); } - public $registerCustomEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void { + public $registerCustomEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: extHostProtocol.IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void { this.registerEditorProvider(CustomEditorModelType.Custom, reviveWebviewExtension(extensionData), viewType, options, {}, supportsMultipleEditorsPerDocument); } @@ -111,7 +110,7 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc modelType: CustomEditorModelType, extension: WebviewExtensionDescription, viewType: string, - options: modes.IWebviewPanelOptions, + options: extHostProtocol.IWebviewPanelOptions, capabilities: extHostProtocol.CustomTextEditorCapabilities, supportsMultipleEditorsPerDocument: boolean, ): void { @@ -176,7 +175,11 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc } try { - await this._proxyCustomEditors.$resolveWebviewEditor(resource, handle, viewType, webviewInput.getTitle(), editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options, cancellation); + await this._proxyCustomEditors.$resolveWebviewEditor(resource, handle, viewType, { + title: webviewInput.getTitle(), + webviewOptions: webviewInput.webview.contentOptions, + panelOptions: webviewInput.webview.options, + }, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), cancellation); } catch (error) { onUnexpectedError(error); webviewInput.webview.html = this.mainThreadWebview.getWebviewResolvedFailedContent(viewType); diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index b918f2db7f1..99809deb23d 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -7,13 +7,14 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { MainThreadWebviews, reviveWebviewExtension, reviveWebviewOptions } from 'vs/workbench/api/browser/mainThreadWebviews'; +import { MainThreadWebviews, reviveWebviewContentOptions, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; -import { editorGroupToViewColumn, EditorGroupColumn, IEditorInput, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; +import { EditorGroupColumn, editorGroupToViewColumn, IEditorInput, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; +import { WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput'; import { WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; -import { ICreateWebViewShowOptions, IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; +import { ICreateWebViewShowOptions, IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -151,9 +152,12 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc extensionData: extHostProtocol.WebviewExtensionDescription, handle: extHostProtocol.WebviewHandle, viewType: string, - title: string, + initData: { + title: string; + webviewOptions: extHostProtocol.IWebviewOptions; + panelOptions: extHostProtocol.IWebviewPanelOptions; + }, showOptions: { viewColumn?: EditorGroupColumn, preserveFocus?: boolean; }, - options: WebviewInputOptions ): void { const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null); if (showOptions) { @@ -163,7 +167,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc const extension = reviveWebviewExtension(extensionData); - const webview = this._webviewWorkbenchService.createWebview(handle, this.webviewPanelViewType.fromExternal(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), extension); + const webview = this._webviewWorkbenchService.createWebview(handle, this.webviewPanelViewType.fromExternal(viewType), initData.title, mainThreadShowOptions, reviveWebviewOptions(initData.panelOptions), reviveWebviewContentOptions(initData.webviewOptions), extension); this.addWebviewInput(handle, webview); /* __GDPR__ @@ -231,7 +235,12 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc } try { - await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options); + await this._proxy.$deserializeWebviewPanel(handle, viewType, { + title: webviewInput.getTitle(), + state, + panelOptions: webviewInput.webview.options, + webviewOptions: webviewInput.webview.contentOptions, + }, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0)); } catch (error) { onUnexpectedError(error); webviewInput.webview.html = this._mainThreadWebviews.getWebviewResolvedFailedContent(viewType); @@ -324,7 +333,6 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc } } - function reviveWebviewIcon( value: { light: UriComponents, dark: UriComponents; } | undefined ): WebviewIcons | undefined { @@ -333,3 +341,9 @@ function reviveWebviewIcon( : undefined; } +function reviveWebviewOptions(panelOptions: extHostProtocol.IWebviewPanelOptions): WebviewOptions { + return { + enableFindWidget: panelOptions.enableFindWidget, + retainContextWhenHidden: panelOptions.retainContextWhenHidden, + }; +} diff --git a/src/vs/workbench/api/browser/mainThreadWebviews.ts b/src/vs/workbench/api/browser/mainThreadWebviews.ts index cd21f731f2a..b49181ee42d 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviews.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviews.ts @@ -8,14 +8,12 @@ import { Schemas } from 'vs/base/common/network'; import { isWeb } from 'vs/base/common/platform'; import { escape } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { IWebviewOptions } from 'vs/editor/common/modes'; import { localize } from 'vs/nls'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IProductService } from 'vs/platform/product/common/productService'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; -import { Webview, WebviewExtensionDescription, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; -import { WebviewInputOptions } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; +import { Webview, WebviewContentOptions, WebviewExtensionDescription, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview'; export class MainThreadWebviews extends Disposable implements extHostProtocol.MainThreadWebviewsShape { @@ -55,9 +53,9 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma webview.html = value; } - public $setOptions(handle: extHostProtocol.WebviewHandle, options: IWebviewOptions): void { + public $setOptions(handle: extHostProtocol.WebviewHandle, options: extHostProtocol.IWebviewOptions): void { const webview = this.getWebview(handle); - webview.contentOptions = reviveWebviewOptions(options); + webview.contentOptions = reviveWebviewContentOptions(options); } public async $postMessage(handle: extHostProtocol.WebviewHandle, message: any): Promise { @@ -120,10 +118,11 @@ export function reviveWebviewExtension(extensionData: extHostProtocol.WebviewExt return { id: extensionData.id, location: URI.revive(extensionData.location) }; } -export function reviveWebviewOptions(options: IWebviewOptions): WebviewInputOptions { +export function reviveWebviewContentOptions(webviewOptions: extHostProtocol.IWebviewOptions): WebviewContentOptions { return { - ...options, - allowScripts: options.enableScripts, - localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(r => URI.revive(r)) : undefined, + allowScripts: webviewOptions.enableScripts, + enableCommandUris: webviewOptions.enableCommandUris, + localResourceRoots: Array.isArray(webviewOptions.localResourceRoots) ? webviewOptions.localResourceRoots.map(r => URI.revive(r)) : undefined, + portMapping: webviewOptions.portMapping, }; } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index cb202b4f28a..dce6fdc93d8 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -592,11 +592,11 @@ export interface MainThreadTelemetryShape extends IDisposable { } export interface MainThreadEditorInsetsShape extends IDisposable { - $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise; + $createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise; $disposeEditorInset(handle: number): void; $setHtml(handle: number, value: string): void; - $setOptions(handle: number, options: modes.IWebviewOptions): void; + $setOptions(handle: number, options: IWebviewOptions): void; $postMessage(handle: number, value: any): Promise; } @@ -646,18 +646,45 @@ export enum WebviewEditorCapabilities { SupportsHotExit, } +export interface IWebviewPortMapping { + readonly webviewPort: number; + readonly extensionHostPort: number; +} + +export interface IWebviewOptions { + readonly enableScripts?: boolean; + readonly enableCommandUris?: boolean; + readonly localResourceRoots?: ReadonlyArray; + readonly portMapping?: ReadonlyArray; +} + +export interface IWebviewPanelOptions { + readonly enableFindWidget?: boolean; + readonly retainContextWhenHidden?: boolean; +} + export interface CustomTextEditorCapabilities { readonly supportsMove?: boolean; } export interface MainThreadWebviewsShape extends IDisposable { $setHtml(handle: WebviewHandle, value: string): void; - $setOptions(handle: WebviewHandle, options: modes.IWebviewOptions): void; + $setOptions(handle: WebviewHandle, options: IWebviewOptions): void; $postMessage(handle: WebviewHandle, value: any): Promise } export interface MainThreadWebviewPanelsShape extends IDisposable { - $createWebviewPanel(extension: WebviewExtensionDescription, handle: WebviewHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions): void; + $createWebviewPanel( + extension: WebviewExtensionDescription, + handle: WebviewHandle, + viewType: string, + initData: { + title: string; + webviewOptions: IWebviewOptions; + panelOptions: IWebviewPanelOptions; + }, + showOptions: WebviewPanelShowOptions, + ): void; $disposeWebview(handle: WebviewHandle): void; $reveal(handle: WebviewHandle, showOptions: WebviewPanelShowOptions): void; $setTitle(handle: WebviewHandle, value: string): void; @@ -668,8 +695,8 @@ export interface MainThreadWebviewPanelsShape extends IDisposable { } export interface MainThreadCustomEditorsShape extends IDisposable { - $registerTextEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, capabilities: CustomTextEditorCapabilities): void; - $registerCustomEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void; + $registerTextEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: IWebviewPanelOptions, capabilities: CustomTextEditorCapabilities): void; + $registerCustomEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void; $unregisterEditorProvider(viewType: string): void; $onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void; @@ -702,11 +729,32 @@ export interface ExtHostWebviewsShape { export interface ExtHostWebviewPanelsShape { $onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void; $onDidDisposeWebviewPanel(handle: WebviewHandle): Promise; - $deserializeWebviewPanel(newWebviewHandle: WebviewHandle, viewType: string, title: string, state: any, position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; + $deserializeWebviewPanel( + newWebviewHandle: WebviewHandle, + viewType: string, + initData: { + title: string; + state: any; + webviewOptions: IWebviewOptions; + panelOptions: IWebviewPanelOptions; + }, + position: EditorGroupColumn, + ): Promise; } export interface ExtHostCustomEditorsShape { - $resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewHandle, viewType: string, title: string, position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken): Promise; + $resolveWebviewEditor( + resource: UriComponents, + newWebviewHandle: WebviewHandle, + viewType: string, + initData: { + title: string; + webviewOptions: IWebviewOptions; + panelOptions: IWebviewPanelOptions; + }, + position: EditorGroupColumn, + cancellation: CancellationToken + ): Promise; $createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken): Promise<{ editable: boolean }>; $disposeCustomDocument(resource: UriComponents, viewType: string): Promise; diff --git a/src/vs/workbench/api/common/extHostCustomEditors.ts b/src/vs/workbench/api/common/extHostCustomEditors.ts index a4359d91a69..4fcf942eec7 100644 --- a/src/vs/workbench/api/common/extHostCustomEditors.ts +++ b/src/vs/workbench/api/common/extHostCustomEditors.ts @@ -9,7 +9,6 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { joinPath } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; -import * as modes from 'vs/editor/common/modes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; @@ -251,9 +250,12 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor resource: UriComponents, handle: extHostProtocol.WebviewHandle, viewType: string, - title: string, + initData: { + title: string; + webviewOptions: extHostProtocol.IWebviewOptions; + panelOptions: extHostProtocol.IWebviewPanelOptions; + }, position: EditorGroupColumn, - options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken, ): Promise { const entry = this._editorProviders.get(viewType); @@ -263,8 +265,8 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor const viewColumn = typeConverters.ViewColumn.to(position); - const webview = this._extHostWebview.createNewWebview(handle, options, entry.extension); - const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview); + const webview = this._extHostWebview.createNewWebview(handle, initData.webviewOptions, entry.extension); + const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, initData.title, viewColumn, initData.panelOptions, webview); const revivedResource = URI.revive(resource); diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 1411775a7a8..d6b9376d018 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -5,7 +5,6 @@ import { Emitter, Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; -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'; @@ -97,7 +96,7 @@ export class ExtHostWebview implements vscode.Webview { public set options(newOptions: vscode.WebviewOptions) { this.assertNotDisposed(); - this.#proxy.$setOptions(this.#handle, convertWebviewOptions(this.#extension, this.#workspace, newOptions)); + this.#proxy.$setOptions(this.#handle, serializeWebviewOptions(this.#extension, this.#workspace, newOptions)); this.#options = newOptions; } @@ -148,7 +147,7 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape { this._logService.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`); } - public createNewWebview(handle: string, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, extension: IExtensionDescription): ExtHostWebview { + public createNewWebview(handle: string, options: extHostProtocol.IWebviewOptions, extension: IExtensionDescription): ExtHostWebview { const webview = new ExtHostWebview(handle, this._webviewProxy, reviveOptions(options), this.initData, this.workspace, extension, this._deprecationService); this._webviews.set(handle, webview); @@ -170,22 +169,24 @@ export function toExtensionData(extension: IExtensionDescription): extHostProtoc return { id: extension.identifier, location: extension.extensionLocation }; } -export function convertWebviewOptions( +export function serializeWebviewOptions( extension: IExtensionDescription, workspace: IExtHostWorkspace | undefined, - options: vscode.WebviewPanelOptions & vscode.WebviewOptions, -): modes.IWebviewOptions { + options: vscode.WebviewOptions, +): extHostProtocol.IWebviewOptions { return { - ...options, + enableCommandUris: options.enableCommandUris, + enableScripts: options.enableScripts, + portMapping: options.portMapping, localResourceRoots: options.localResourceRoots || getDefaultLocalResourceRoots(extension, workspace) }; } -function reviveOptions( - options: modes.IWebviewOptions & modes.IWebviewPanelOptions -): vscode.WebviewOptions { +export function reviveOptions(options: extHostProtocol.IWebviewOptions): vscode.WebviewOptions { return { - ...options, + enableCommandUris: options.enableCommandUris, + enableScripts: options.enableScripts, + portMapping: options.portMapping, localResourceRoots: options.localResourceRoots?.map(components => URI.from(components)), }; } diff --git a/src/vs/workbench/api/common/extHostWebviewPanels.ts b/src/vs/workbench/api/common/extHostWebviewPanels.ts index dfdd948be50..3e30cffcf47 100644 --- a/src/vs/workbench/api/common/extHostWebviewPanels.ts +++ b/src/vs/workbench/api/common/extHostWebviewPanels.ts @@ -7,10 +7,9 @@ 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 { serializeWebviewOptions, ExtHostWebview, ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; import { EditorGroupColumn } from 'vs/workbench/common/editor'; import type * as vscode from 'vscode'; @@ -48,14 +47,14 @@ class ExtHostWebviewPanel extends Disposable implements vscode.WebviewPanel { viewType: string, title: string, viewColumn: vscode.ViewColumn | undefined, - editorOptions: vscode.WebviewPanelOptions, + panelOptions: vscode.WebviewPanelOptions, webview: ExtHostWebview ) { super(); this.#handle = handle; this.#proxy = proxy; this.#viewType = viewType; - this.#options = editorOptions; + this.#options = panelOptions; this.#viewColumn = viewColumn; this.#title = title; this.#webview = webview; @@ -201,7 +200,11 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel }; const handle = ExtHostWebviewPanels.newHandle(); - this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options)); + this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, { + title, + panelOptions: serializeWebviewPanelOptions(options), + webviewOptions: serializeWebviewOptions(extension, this.workspace, options), + }, webviewShowOptions); const webview = this.webviews.createNewWebview(handle, options, extension); const panel = this.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview); @@ -271,10 +274,13 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel async $deserializeWebviewPanel( webviewHandle: extHostProtocol.WebviewHandle, viewType: string, - title: string, - state: any, - position: EditorGroupColumn, - options: modes.IWebviewOptions & modes.IWebviewPanelOptions + initData: { + title: string; + state: any; + webviewOptions: extHostProtocol.IWebviewOptions; + panelOptions: extHostProtocol.IWebviewPanelOptions; + }, + position: EditorGroupColumn ): Promise { const entry = this._serializers.get(viewType); if (!entry) { @@ -282,12 +288,12 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel } 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); + const webview = this.webviews.createNewWebview(webviewHandle, initData.webviewOptions, extension); + const revivedPanel = this.createNewWebviewPanel(webviewHandle, viewType, initData.title, position, initData.panelOptions, webview); + await serializer.deserializeWebviewPanel(revivedPanel, initData.state); } - public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: vscode.ViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, webview: ExtHostWebview) { + public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: vscode.ViewColumn, options: extHostProtocol.IWebviewPanelOptions, webview: ExtHostWebview) { const panel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, position, options, webview); this._webviewPanels.set(webviewHandle, panel); return panel; @@ -297,3 +303,10 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel return this._webviewPanels.get(handle); } } + +function serializeWebviewPanelOptions(options: vscode.WebviewPanelOptions): extHostProtocol.IWebviewPanelOptions { + return { + enableFindWidget: options.enableFindWidget, + retainContextWhenHidden: options.retainContextWhenHidden, + }; +} diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts index c35707544aa..192cb111a30 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInputFactory.ts @@ -7,9 +7,9 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICustomEditorInputFactory, IEditorInput } from 'vs/workbench/common/editor'; import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; -import { IWebviewService, WebviewContentPurpose, WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview'; -import { DeserializedWebview, reviveWebviewExtensionDescription, SerializedWebview, WebviewEditorInputFactory } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInputFactory'; -import { IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; +import { IWebviewService, WebviewContentOptions, WebviewContentPurpose, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; +import { SerializedWebviewOptions, DeserializedWebview, reviveWebviewExtensionDescription, SerializedWebview, WebviewEditorInputFactory, restoreWebviewContentOptions, restoreWebviewOptions } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInputFactory'; +import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; export interface CustomDocumentBackupData { @@ -24,7 +24,7 @@ export interface CustomDocumentBackupData { readonly webview: { readonly id: string; - readonly options: WebviewInputOptions; + readonly options: SerializedWebviewOptions; readonly state: any; }; } @@ -84,7 +84,7 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory { serializedEditorInput: string ): CustomEditorInput { const data = this.fromJson(JSON.parse(serializedEditorInput)); - const webview = reviveWebview(data, this._webviewService); + const webview = reviveWebview(this._webviewService, data); const customInput = this._instantiationService.createInstance(CustomEditorInput, data.editorResource, data.viewType, data.id, webview, { startsDirty: data.dirty, backupId: data.backupId }); if (typeof data.group === 'number') { customInput.updateGroup(data.group); @@ -93,12 +93,12 @@ export class CustomEditorInputFactory extends WebviewEditorInputFactory { } } -function reviveWebview(data: { id: string, state: any, options: WebviewInputOptions, extension?: WebviewExtensionDescription, }, webviewService: IWebviewService) { +function reviveWebview(webviewService: IWebviewService, data: { id: string, state: any, webviewOptions: WebviewOptions, contentOptions: WebviewContentOptions, extension?: WebviewExtensionDescription, }) { const webview = webviewService.createWebviewOverlay(data.id, { purpose: WebviewContentPurpose.CustomEditor, - enableFindWidget: data.options.enableFindWidget, - retainContextWhenHidden: data.options.retainContextWhenHidden - }, data.options, data.extension); + enableFindWidget: data.webviewOptions.enableFindWidget, + retainContextWhenHidden: data.webviewOptions.retainContextWhenHidden + }, data.contentOptions, data.extension); webview.state = data.state; return webview; } @@ -117,7 +117,13 @@ export const customEditorInputFactory = new class implements ICustomEditorInputF const backupData = backup.meta; const id = backupData.webview.id; const extension = reviveWebviewExtensionDescription(backupData.extension?.id, backupData.extension?.location); - const webview = reviveWebview({ id, options: backupData.webview.options, state: backupData.webview.state, extension, }, webviewService); + const webview = reviveWebview(webviewService, { + id, + webviewOptions: restoreWebviewOptions(backupData.webview.options), + contentOptions: restoreWebviewContentOptions(backupData.webview.options), + state: backupData.webview.state, + extension, + }); const editor = instantiationService.createInstance(CustomEditorInput, URI.revive(backupData.editorResource), backupData.viewType, id, webview, { backupId: backupData.backupId }); editor.updateGroup(0); diff --git a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts index fa486e25497..631aba78e1b 100644 --- a/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts +++ b/src/vs/workbench/contrib/update/browser/releaseNotesEditor.ts @@ -84,6 +84,8 @@ export class ReleaseNotesManager { { tryRestoreScrollPosition: true, enableFindWidget: true, + }, + { localResourceRoots: [] }, undefined); diff --git a/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts index c4ece0e2bff..2c3f6c87d3e 100644 --- a/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/baseWebviewElement.ts @@ -13,8 +13,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/browser/themeing'; -import { WebviewContentOptions, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; -import { areWebviewInputOptionsEqual } from 'vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService'; +import { areWebviewContentOptionsEqual, WebviewContentOptions, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; export const enum WebviewMessageChannels { @@ -275,7 +274,7 @@ export abstract class BaseWebview extends Disposable { public set contentOptions(options: WebviewContentOptions) { this._logService.debug(`Webview(${this.id}): will update content options`); - if (areWebviewInputOptionsEqual(options, this.content.options)) { + if (areWebviewContentOptionsEqual(options, this.content.options)) { this._logService.debug(`Webview(${this.id}): skipping content options update`); return; } diff --git a/src/vs/workbench/contrib/webview/browser/webview.ts b/src/vs/workbench/contrib/webview/browser/webview.ts index dba3fe30fd2..63b8303ad67 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.ts @@ -5,13 +5,15 @@ import { Dimension } from 'vs/base/browser/dom'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +import { equals } from 'vs/base/common/arrays'; import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { isEqual } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import * as modes from 'vs/editor/common/modes'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IWebviewPortMapping } from 'vs/platform/webview/common/webviewPortMapping'; /** * Set when the find widget in a webview is visible. @@ -75,10 +77,20 @@ export interface WebviewContentOptions { readonly allowMultipleAPIAcquire?: boolean; readonly allowScripts?: boolean; readonly localResourceRoots?: ReadonlyArray; - readonly portMapping?: ReadonlyArray; + readonly portMapping?: ReadonlyArray; readonly enableCommandUris?: boolean; } +export function areWebviewContentOptionsEqual(a: WebviewContentOptions, b: WebviewContentOptions): boolean { + return ( + a.allowMultipleAPIAcquire === b.allowMultipleAPIAcquire + && a.allowScripts === b.allowScripts + && equals(a.localResourceRoots, b.localResourceRoots, isEqual) + && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort) + && a.enableCommandUris === b.enableCommandUris + ); +} + export interface WebviewExtensionDescription { readonly location: URI; readonly id: ExtensionIdentifier; diff --git a/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts b/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts index ae34e875e1a..1c7d7155240 100644 --- a/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts +++ b/src/vs/workbench/contrib/webview/electron-sandbox/resourceLoading.ts @@ -11,7 +11,6 @@ import { Schemas } from 'vs/base/common/network'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc'; import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals'; -import * as modes from 'vs/editor/common/modes'; import { IFileService } from 'vs/platform/files/common/files'; import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services'; import { ILogService } from 'vs/platform/log/common/log'; @@ -20,6 +19,7 @@ import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remot import { IRequestService } from 'vs/platform/request/common/request'; import { loadLocalResource, readFileStream, WebviewResourceResponse } from 'vs/platform/webview/common/resourceLoader'; import { IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService'; +import { IWebviewPortMapping } from 'vs/platform/webview/common/webviewPortMapping'; import { WebviewContentOptions, WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -51,7 +51,7 @@ export class WebviewResourceRequestManager extends Disposable { private readonly _webviewManagerService: IWebviewManagerService; private _localResourceRoots: ReadonlyArray; - private _portMappings: ReadonlyArray; + private _portMappings: ReadonlyArray; private _ready: Promise; @@ -164,7 +164,7 @@ export class WebviewResourceRequestManager extends Disposable { private needsUpdate( localResourceRoots: readonly URI[], - portMappings: readonly modes.IWebviewPortMapping[], + portMappings: readonly IWebviewPortMapping[], ): boolean { return !( equals(this._localResourceRoots, localResourceRoots, (a, b) => a.toString() === b.toString()) diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputFactory.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputFactory.ts index b854f9ef554..91a9fb96510 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputFactory.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewEditorInputFactory.ts @@ -7,10 +7,12 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorInputFactory } from 'vs/workbench/common/editor'; -import { WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview'; +import { WebviewContentOptions, WebviewExtensionDescription, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewIcons } from 'vs/workbench/contrib/webviewPanel/browser/webviewIconManager'; import { WebviewInput } from './webviewEditorInput'; -import { IWebviewWorkbenchService, WebviewInputOptions } from './webviewWorkbenchService'; +import { IWebviewWorkbenchService } from './webviewWorkbenchService'; + +export type SerializedWebviewOptions = WebviewOptions & WebviewContentOptions; interface SerializedIconPath { light: string | UriComponents; @@ -21,7 +23,7 @@ export interface SerializedWebview { readonly id: string; readonly viewType: string; readonly title: string; - readonly options: WebviewInputOptions; + readonly options: SerializedWebviewOptions; readonly extensionLocation: UriComponents | undefined; readonly extensionId: string | undefined; readonly state: any; @@ -33,7 +35,8 @@ export interface DeserializedWebview { readonly id: string; readonly viewType: string; readonly title: string; - readonly options: WebviewInputOptions; + readonly webviewOptions: WebviewOptions; + readonly contentOptions: WebviewContentOptions; readonly extension: WebviewExtensionDescription | undefined; readonly state: any; readonly iconPath: WebviewIcons | undefined; @@ -76,7 +79,8 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { title: data.title, iconPath: data.iconPath, state: data.state, - options: data.options, + webviewOptions: data.webviewOptions, + contentOptions: data.contentOptions, extension: data.extension, group: data.group }); @@ -88,7 +92,8 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { extension: reviveWebviewExtensionDescription(data.extensionId, data.extensionLocation), iconPath: reviveIconPath(data.iconPath), state: reviveState(data.state), - options: reviveOptions(data.options) + webviewOptions: restoreWebviewOptions(data.options), + contentOptions: restoreWebviewContentOptions(data.options), }; } @@ -157,7 +162,11 @@ function reviveState(state: unknown | undefined): undefined | string { return typeof state === 'string' ? state : undefined; } -function reviveOptions(options: WebviewInputOptions): WebviewInputOptions { +export function restoreWebviewOptions(options: SerializedWebviewOptions): WebviewOptions { + return options; +} + +export function restoreWebviewContentOptions(options: SerializedWebviewOptions): WebviewContentOptions { return { ...options, localResourceRoots: options.localResourceRoots?.map(uri => reviveUri(uri)), diff --git a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts index 12a9973599e..8e776fc388b 100644 --- a/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts +++ b/src/vs/workbench/contrib/webviewPanel/browser/webviewWorkbenchService.ts @@ -3,14 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { equals } from 'vs/base/common/arrays'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { memoize } from 'vs/base/common/decorators'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { Iterable } from 'vs/base/common/iterator'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { isEqual } from 'vs/base/common/resources'; import { EditorActivation } from 'vs/platform/editor/common/editor'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { GroupIdentifier } from 'vs/workbench/common/editor'; @@ -27,23 +25,6 @@ export interface ICreateWebViewShowOptions { preserveFocus: boolean; } -export interface WebviewInputOptions extends WebviewOptions, WebviewContentOptions { - readonly tryRestoreScrollPosition?: boolean; - readonly retainContextWhenHidden?: boolean; - readonly enableCommandUris?: boolean; -} - -export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewInputOptions): boolean { - return a.enableCommandUris === b.enableCommandUris - && a.enableFindWidget === b.enableFindWidget - && a.allowScripts === b.allowScripts - && a.allowMultipleAPIAcquire === b.allowMultipleAPIAcquire - && a.retainContextWhenHidden === b.retainContextWhenHidden - && a.tryRestoreScrollPosition === b.tryRestoreScrollPosition - && equals(a.localResourceRoots, b.localResourceRoots, isEqual) - && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort); -} - export interface IWebviewWorkbenchService { readonly _serviceBrand: undefined; @@ -54,7 +35,8 @@ export interface IWebviewWorkbenchService { viewType: string, title: string, showOptions: ICreateWebViewShowOptions, - options: WebviewInputOptions, + webviewOptions: WebviewOptions, + contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined, ): WebviewInput; @@ -64,7 +46,8 @@ export interface IWebviewWorkbenchService { title: string, iconPath: WebviewIcons | undefined, state: any, - options: WebviewInputOptions, + webviewOptions: WebviewOptions, + contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined, group: number | undefined }): WebviewInput; @@ -199,10 +182,11 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc viewType: string, title: string, showOptions: ICreateWebViewShowOptions, - options: WebviewInputOptions, + webviewOptions: WebviewOptions, + contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined, ): WebviewInput { - const webview = this.createWebviewElement(id, extension, options); + const webview = this._webviewService.createWebviewOverlay(id, webviewOptions, contentOptions, extension); const webviewInput = this._instantiationService.createInstance(WebviewInput, id, viewType, title, webview, this.iconManager); this._editorService.openEditor(webviewInput, { pinned: true, @@ -240,11 +224,12 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc title: string, iconPath: WebviewIcons | undefined, state: any, - options: WebviewInputOptions, + webviewOptions: WebviewOptions, + contentOptions: WebviewContentOptions, extension: WebviewExtensionDescription | undefined, group: number | undefined, }): WebviewInput { - const webview = this.createWebviewElement(options.id, options.extension, options.options); + const webview = this._webviewService.createWebviewOverlay(options.id, options.webviewOptions, options.contentOptions, options.extension); webview.state = options.state; const webviewInput = this._instantiationService.createInstance(LazilyResolvedWebviewEditorInput, options.id, options.viewType, options.title, webview); @@ -313,15 +298,4 @@ export class WebviewEditorService extends Disposable implements IWebviewWorkbenc public setIcons(id: string, iconPath: WebviewIcons | undefined): void { this._iconManager.setIcons(id, iconPath); } - - private createWebviewElement( - id: string, - extension: WebviewExtensionDescription | undefined, - options: WebviewInputOptions, - ) { - return this._webviewService.createWebviewOverlay(id, { - enableFindWidget: options.enableFindWidget, - retainContextWhenHidden: options.retainContextWhenHidden - }, options, extension); - } } diff --git a/src/vs/workbench/test/browser/api/extHostWebview.test.ts b/src/vs/workbench/test/browser/api/extHostWebview.test.ts index 32854e82cad..554f8ab862d 100644 --- a/src/vs/workbench/test/browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/browser/api/extHostWebview.test.ts @@ -53,7 +53,12 @@ suite('ExtHostWebview', () => { const serializerARegistration = extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerA); - await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorGroupColumn, {}); + await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, { + title: 'title', + state: {}, + panelOptions: {}, + webviewOptions: {} + }, 0 as EditorGroupColumn); assert.strictEqual(lastInvokedDeserializer, serializerA); assert.throws( @@ -64,7 +69,12 @@ suite('ExtHostWebview', () => { extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB); - await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorGroupColumn, {}); + await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, { + title: 'title', + state: {}, + panelOptions: {}, + webviewOptions: {} + }, 0 as EditorGroupColumn); assert.strictEqual(lastInvokedDeserializer, serializerB); });