diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts index 4189615c09ebf1cda435521d39785777baacb59e..c927c15c3445fccc0d99a4a82103d532d7c4eb7a 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { env, extensions, ExtensionKind, UIKind } from 'vscode'; +import { env, extensions, ExtensionKind, UIKind, Uri } from 'vscode'; suite('env-namespace', () => { @@ -45,8 +45,29 @@ suite('env-namespace', () => { } }); - test('env.uiKind', function () { + test('env.uiKind', async function () { + const uri = Uri.parse(`${env.uriScheme}:://vscode.vscode-api-tests/path?key=value&other=false`); + const result = await env.asExternalUri(uri); + const kind = env.uiKind; - assert.equal(kind, UIKind.Desktop); + if (result.scheme === 'http' || result.scheme === 'https') { + assert.equal(kind, UIKind.Web); + } else { + assert.equal(kind, UIKind.Desktop); + } + }); + + test('env.asExternalUri - with env.uriScheme', async function () { + const uri = Uri.parse(`${env.uriScheme}:://vscode.vscode-api-tests/path?key=value&other=false`); + const result = await env.asExternalUri(uri); + assert.ok(result); + + if (env.uiKind === UIKind.Desktop) { + assert.equal(uri.scheme, result.scheme); + assert.equal(uri.authority, result.authority); + assert.equal(uri.path, result.path); + } else { + assert.ok(result.scheme === 'http' || result.scheme === 'https'); + } }); }); diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index 2de51e8d32488d0ea77d3e65e69f9b02c5c9c74c..6f76dd1680f430d441c7f680f95c628cfd5fa71d 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -23,7 +23,8 @@ if (isWeb) { assign(product, { version: '1.39.0-dev', nameLong: 'Visual Studio Code Web Dev', - nameShort: 'VSCode Web Dev' + nameShort: 'VSCode Web Dev', + urlProtocol: 'code-oss' }); } } diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 908e242693e696f77afff7f540060725871a4931..ec9cc035c5067db46f9f76a3a09d2b7ac74a49f8 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -6433,22 +6433,51 @@ declare module 'vscode' { export function openExternal(target: Uri): Thenable; /** + * Resolves a uri to form that is accessible externally. Currently only supports `https:`, `http:` and + * `vscode.env.uriScheme` uris. + * + * #### `http:` or `https:` scheme + * * Resolves an *external* uri, such as a `http:` or `https:` link, from where the extension is running to a * uri to the same resource on the client machine. * - * This is a no-op if the extension is running on the client machine. Currently only supports - * `https:` and `http:` uris. + * This is a no-op if the extension is running on the client machine. * * If the extension is running remotely, this function automatically establishes a port forwarding tunnel * from the local machine to `target` on the remote and returns a local uri to the tunnel. The lifetime of * the port fowarding tunnel is managed by VS Code and the tunnel can be closed by the user. * - * Extensions should not cache the result of `asExternalUri` as the resolved uri may become invalid due to - * a system or user action — for example, in remote cases, a user may close a port forwardng tunnel - * that was opened by `asExternalUri`. + * *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` on them. + * + * #### `vscode.env.uriScheme` + * + * Creates a uri that - if opened in a browser (e.g. via `openExternal`) - will result in a registered [UriHandler](#UriHandler) + * to trigger. + * + * Extensions should not make any assumptions about the resulting uri and should not alter it in anyway. + * Rather, extensions can e.g. use this uri in an authentication flow, by adding the uri as callback query + * argument to the server to authenticate to. + * + * *Note* that if the server decides to add additional query parameters to the uri (e.g. a token or secret), it + * will appear in the uri that is passed to the [UriHandler](#UriHandler). + * + * **Example** of an authentication flow: + * ```typescript + * vscode.window.registerUriHandler({ + * handleUri(uri: vscode.Uri): vscode.ProviderResult { + * if (uri.path === '/did-authenticate') { + * console.log(uri.toString()); + * } + * } + * }); + * + * const callableUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${env.uriScheme}:://my.extension/did-authenticate`)); + * await vscode.env.openExternal(callableUri); + * ``` * - * *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` - * on them. + * *Note* that extensions should not cache the result of `asExternalUri` as the resolved uri may become invalid due to + * a system or user action — for example, in remote cases, a user may close a port forwarding tunnel that was opened by + * `asExternalUri`. * * @return A uri that can be used on the client machine. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 61705756a25ef3bf6547ef3bfb9677caa899e31b..22067687355fd0902d151ca14b65cd98345b3121 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -855,33 +855,7 @@ declare module 'vscode' { export namespace env { /** - * Creates a Uri that - if opened in a browser - will result in a - * registered [UriHandler](#UriHandler) to fire. The handler's - * Uri will be configured with the path, query and fragment of - * [AppUriOptions](#AppUriOptions) if provided, otherwise it will be empty. - * - * Extensions should not make any assumptions about the resulting - * Uri and should not alter it in anyway. Rather, extensions can e.g. - * use this Uri in an authentication flow, by adding the Uri as - * callback query argument to the server to authenticate to. - * - * Note: If the server decides to add additional query parameters to the Uri - * (e.g. a token or secret), it will appear in the Uri that is passed - * to the [UriHandler](#UriHandler). - * - * **Example** of an authentication flow: - * ```typescript - * vscode.window.registerUriHandler({ - * handleUri(uri: vscode.Uri): vscode.ProviderResult { - * if (uri.path === '/did-authenticate') { - * console.log(uri.toString()); - * } - * } - * }); - * - * const callableUri = await vscode.env.createAppUri({ payload: { path: '/did-authenticate' } }); - * await vscode.env.openExternal(callableUri); - * ``` + * @deprecated use `vscode.env.asExternalUri` instead. */ export function createAppUri(options?: AppUriOptions): Thenable; } diff --git a/src/vs/workbench/api/browser/mainThreadUrls.ts b/src/vs/workbench/api/browser/mainThreadUrls.ts index a89f291d6c25266ac866c9a4abdfde76b48689e0..beda98076af2682a2fe6ad8bbc6df7589cd28b5d 100644 --- a/src/vs/workbench/api/browser/mainThreadUrls.ts +++ b/src/vs/workbench/api/browser/mainThreadUrls.ts @@ -68,7 +68,11 @@ export class MainThreadUrls implements MainThreadUrlsShape { return Promise.resolve(undefined); } - async $createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise { + async $createAppUri(uri: UriComponents): Promise { + return this.urlService.create(uri); + } + + async $proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise { const payload: Partial = options && options.payload ? options.payload : Object.create(null); // we define the authority to be the extension ID to ensure diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 11968b623782f8fa043d5b22d11b108b9a78dfd3..5b5a76c6fc0fc0f6d47ae9248572b767e7d90d6a 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -228,7 +228,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I get uriScheme() { return initData.environment.appUriScheme; }, createAppUri(options?) { checkProposedApiEnabled(extension); - return extHostUrls.createAppUri(extension.identifier, options); + return extHostUrls.proposedCreateAppUri(extension.identifier, options); }, get logLevel() { checkProposedApiEnabled(extension); @@ -248,6 +248,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, asExternalUri(uri: URI) { + if (uri.scheme === initData.environment.appUriScheme) { + return extHostUrls.createAppUri(uri); + } + return extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, get remoteName() { diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index b8f4e05cc2daf6bbd33a00d107687fe77c7751fe..acb3246bef7ca1e66736da8b6a1d67f91ae6b8ff 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -594,7 +594,8 @@ export interface ExtHostWebviewsShape { export interface MainThreadUrlsShape extends IDisposable { $registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise; $unregisterUriHandler(handle: number): Promise; - $createAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise; + $createAppUri(uri: UriComponents): Promise; + $proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: { payload?: Partial }): Promise; } export interface ExtHostUrlsShape { diff --git a/src/vs/workbench/api/common/extHostUrls.ts b/src/vs/workbench/api/common/extHostUrls.ts index 6b6f8081ae58f15f5da1956aa85bd467e24cf9aa..0a4480a63e84dfe3c31d26c876ad446b8a8d2ded 100644 --- a/src/vs/workbench/api/common/extHostUrls.ts +++ b/src/vs/workbench/api/common/extHostUrls.ts @@ -56,7 +56,11 @@ export class ExtHostUrls implements ExtHostUrlsShape { return Promise.resolve(undefined); } - async createAppUri(extensionId: ExtensionIdentifier, options?: vscode.AppUriOptions): Promise { - return URI.revive(await this._proxy.$createAppUri(extensionId, options)); + async createAppUri(uri: URI): Promise { + return URI.revive(await this._proxy.$createAppUri(uri)); + } + + async proposedCreateAppUri(extensionId: ExtensionIdentifier, options?: vscode.AppUriOptions): Promise { + return URI.revive(await this._proxy.$proposedCreateAppUri(extensionId, options)); } } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 26ccbe6f9ea5abd39950ad5149834549cb003752..665523c0bf5d8b1836129e3e52272d522a36be79 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -162,10 +162,7 @@ class BrowserMain extends Disposable { // Product const productService = { _serviceBrand: undefined, - ...{ - ...product, // dev or built time config - ...{ urlProtocol: '' } // web related overrides from us - } + ...product }; serviceCollection.set(IProductService, productService);