diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index d17a34fbf0c..45f6f17ce06 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IApplicationLinkProvider, IApplicationLink } from 'vs/workbench/workbench.web.api'; +import { IWorkbenchConstructionOptions, create, URI, Event, Emitter, UriComponents, ICredentialsProvider, IURLCallbackProvider, IWorkspaceProvider, IWorkspace, IApplicationLink } from 'vs/workbench/workbench.web.api'; import { generateUuid } from 'vs/base/common/uuid'; import { CancellationToken } from 'vs/base/common/cancellation'; import { streamToBuffer } from 'vs/base/common/buffer'; @@ -279,39 +279,6 @@ class WorkspaceProvider implements IWorkspaceProvider { } } -class ApplicationLinkProvider { - - private links: IApplicationLink[] | undefined = undefined; - - constructor(workspace: IWorkspace) { - this.computeLink(workspace); - } - - private computeLink(workspace: IWorkspace): void { - if (!workspace) { - return; // not for empty workspaces - } - - const workspaceUri = isWorkspaceToOpen(workspace) ? workspace.workspaceUri : isFolderToOpen(workspace) ? workspace.folderUri : undefined; - if (workspaceUri) { - this.links = [{ - uri: URI.from({ - scheme: product.quality === 'stable' ? 'vscode' : 'vscode-insiders', - authority: Schemas.vscodeRemote, - path: posix.join(posix.sep, workspaceUri.authority, workspaceUri.path), - query: workspaceUri.query, - fragment: workspaceUri.fragment, - }), - label: localize('openInDesktop', "Open in Desktop") - }]; - } - } - - get provider(): IApplicationLinkProvider { - return () => this.links; - } -} - (function () { // Find config by checking for DOM @@ -375,12 +342,30 @@ class ApplicationLinkProvider { } } + // Application links ("Open in Desktop") + let applicationLinks: IApplicationLink[] | undefined = undefined; + if (workspace) { + const workspaceUri = isWorkspaceToOpen(workspace) ? workspace.workspaceUri : isFolderToOpen(workspace) ? workspace.folderUri : undefined; + if (workspaceUri) { + applicationLinks = [{ + uri: URI.from({ + scheme: product.quality === 'stable' ? 'vscode' : 'vscode-insiders', + authority: Schemas.vscodeRemote, + path: posix.join(posix.sep, workspaceUri.authority, workspaceUri.path), + query: workspaceUri.query, + fragment: workspaceUri.fragment, + }), + label: localize('openInDesktop', "Open in Desktop") + }]; + } + } + // Finally create workbench create(document.body, { ...config, workspaceProvider: new WorkspaceProvider(workspace, payload), urlCallbackProvider: new PollingURLCallbackProvider(), credentialsProvider: new LocalStorageCredentialsProvider(), - applicationLinkProvider: new ApplicationLinkProvider(workspace).provider + applicationLinks: applicationLinks }); })(); diff --git a/src/vs/workbench/contrib/openInDesktop/browser/openInDesktop.web.contribution.ts b/src/vs/workbench/contrib/openInDesktop/browser/openInDesktop.web.contribution.ts index 0b959f3abd4..9854d0f0628 100644 --- a/src/vs/workbench/contrib/openInDesktop/browser/openInDesktop.web.contribution.ts +++ b/src/vs/workbench/contrib/openInDesktop/browser/openInDesktop.web.contribution.ts @@ -29,13 +29,13 @@ export class OpenInDesktopIndicator extends Disposable implements IWorkbenchCont ) { super(); - const links = environmentService.options?.applicationLinkProvider?.(); + const links = environmentService.options?.applicationLinks; if (Array.isArray(links) && links?.length > 0) { this.installOpenInDesktopIndicator(links); } } - private installOpenInDesktopIndicator(links: IApplicationLink[]): void { + private installOpenInDesktopIndicator(links: readonly IApplicationLink[]): void { // Register action to trigger "Open In Desktop" const registry = Registry.as(ActionExtensions.WorkbenchActions); @@ -71,7 +71,7 @@ export class OpenInDesktopAction extends Action { } async run(): Promise { - const links = this.environmentService.options?.applicationLinkProvider?.(); + const links = this.environmentService.options?.applicationLinks; if (Array.isArray(links)) { if (links.length === 1) { return this.openApplicationLink(links[0]); @@ -83,7 +83,7 @@ export class OpenInDesktopAction extends Action { return true; } - private async runWithPicker(links: IApplicationLink[]): Promise { + private async runWithPicker(links: readonly IApplicationLink[]): Promise { // Show a picker with choices const quickPick = this.quickInputService.createQuickPick(); diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 4cd646930bb..140711b300e 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -80,17 +80,29 @@ interface IApplicationLink { uri: URI; /** - * A label for the link to display. + * A label for the application link to display. */ label: string; } -interface IApplicationLinkProvider { - (): IApplicationLink[] | undefined +interface ICommand { + + /** + * An identifier for the command. Commands can be executed from extensions + * using the `vscode.commands.executeCommand` API using that command ID. + */ + id: string, + + /** + * A function that is being executed with any arguments passed over. + */ + handler: (...args: any[]) => void; } interface IWorkbenchConstructionOptions { + //#region Connection related configuration + /** * The remote authority is the IP:PORT from where the workbench is served * from. It is for example being used for the websocket connections as address. @@ -108,6 +120,36 @@ interface IWorkbenchConstructionOptions { */ readonly webviewEndpoint?: string; + /** + * A factory for web sockets. + */ + readonly webSocketFactory?: IWebSocketFactory; + + /** + * A provider for resource URIs. + */ + readonly resourceUriProvider?: IResourceUriProvider; + + /** + * Resolves an external uri before it is opened. + */ + readonly resolveExternalUri?: IExternalUriResolver; + + /** + * Support for creating tunnels. + */ + readonly tunnelFactory?: ITunnelFactory; + + /** + * Support for filtering candidate ports + */ + readonly showCandidate?: IShowCandidate; + + //#endregion + + + //#region Workbench configuration + /** * A handler for opening workspaces and providing the initial workspace. */ @@ -119,16 +161,6 @@ interface IWorkbenchConstructionOptions { */ userDataProvider?: IFileSystemProvider; - /** - * A factory for web sockets. - */ - readonly webSocketFactory?: IWebSocketFactory; - - /** - * A provider for resource URIs. - */ - readonly resourceUriProvider?: IResourceUriProvider; - /** * The credentials provider to store and retrieve secrets. */ @@ -154,21 +186,6 @@ interface IWorkbenchConstructionOptions { */ readonly resolveCommonTelemetryProperties?: ICommontTelemetryPropertiesResolver; - /** - * Resolves an external uri before it is opened. - */ - readonly resolveExternalUri?: IExternalUriResolver; - - /** - * Support for creating tunnels. - */ - readonly tunnelFactory?: ITunnelFactory; - - /** - * Support for filtering candidate ports - */ - readonly showCandidate?: IShowCandidate; - /** * Provide entries for the "Open in Desktop" feature. * @@ -179,7 +196,20 @@ interface IWorkbenchConstructionOptions { * - N elements: there will be a "Open in Desktop" affordance that opens * a picker on click to select which application to open. */ - readonly applicationLinkProvider?: IApplicationLinkProvider; + readonly applicationLinks?: readonly IApplicationLink[]; + + /** + * A set of optional commands that should be registered with the commands + * registry. + * + * Note: commands can be called from extensions if the identifier is known! + */ + readonly commands?: readonly ICommand[]; + + //#endregion + + + //#region Diagnostics /** * Current logging level. Default is `LogLevel.Info`. @@ -190,20 +220,8 @@ interface IWorkbenchConstructionOptions { * Whether to enable the smoke test driver. */ readonly driver?: boolean; -} -interface ICommandHandler { - (...args: any[]): void; -} - -interface IWorkbench { - - /** - * Register a command with the provided identifier and handler with - * the workbench. The command can be called from extensions using the - * `vscode.commands.executeCommand` API. - */ - registerCommand(id: string, command: ICommandHandler): IDisposable; + //#endregion } /** @@ -211,24 +229,22 @@ interface IWorkbench { * * @param domElement the container to create the workbench in * @param options for setting up the workbench - * - * @returns the workbench facade with additional methods to call on. */ -async function create(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise { +async function create(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise { // Startup workbench await main(domElement, options); - // Return facade - return { - registerCommand: (id: string, command: ICommandHandler): IDisposable => { - return CommandsRegistry.registerCommand(id, (accessor, ...args: any[]) => { + // Register commands if any + if (Array.isArray(options.commands)) { + for (const command of options.commands) { + CommandsRegistry.registerCommand(command.id, (accessor, ...args: any[]) => { // we currently only pass on the arguments but not the accessor // to the command to reduce our exposure of internal API. - command(...args); + command.handler(...args); }); } - }; + } } export { @@ -237,9 +253,6 @@ export { create, IWorkbenchConstructionOptions, - // Workbench Facade - IWorkbench, - ICommandHandler, // Basic Types URI, @@ -291,5 +304,7 @@ export { // Protocol Links IApplicationLink, - IApplicationLinkProvider + + // Commands + ICommand };