diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index 5063bef9392f7..b71e6f295676d 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -533,6 +533,10 @@ export enum TreeViewItemCollapsibleState { Expanded = 2 } +export interface WindowMain { + $openUri(uri: UriComponents): Promise; +} + export interface WindowStateExt { $onWindowStateChanged(focus: boolean): void; } @@ -1269,7 +1273,8 @@ export const PLUGIN_RPC_CONTEXT = { DEBUG_MAIN: createProxyIdentifier('DebugMain'), FILE_SYSTEM_MAIN: createProxyIdentifier('FileSystemMain'), SCM_MAIN: createProxyIdentifier('ScmMain'), - DECORATIONS_MAIN: createProxyIdentifier('DecorationsMain') + DECORATIONS_MAIN: createProxyIdentifier('DecorationsMain'), + WINDOW_MAIN: createProxyIdentifier('WindowMain') }; export const MAIN_RPC_CONTEXT = { diff --git a/packages/plugin-ext/src/main/browser/main-context.ts b/packages/plugin-ext/src/main/browser/main-context.ts index ad5746e27fd69..72e606cf3ca57 100644 --- a/packages/plugin-ext/src/main/browser/main-context.ts +++ b/packages/plugin-ext/src/main/browser/main-context.ts @@ -61,7 +61,6 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container rpc.set(PLUGIN_RPC_CONTEXT.PREFERENCE_REGISTRY_MAIN, preferenceRegistryMain); /* tslint:disable */ - new WindowStateMain(rpc); new EditorsAndDocumentsMain(rpc, container); /* tslint:enable */ @@ -111,4 +110,7 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container const decorationsMain = new DecorationsMainImpl(rpc, container); rpc.set(PLUGIN_RPC_CONTEXT.DECORATIONS_MAIN, decorationsMain); + + const windowMain = new WindowStateMain(rpc, container); + rpc.set(PLUGIN_RPC_CONTEXT.WINDOW_MAIN, windowMain); } diff --git a/packages/plugin-ext/src/main/browser/window-state-main.ts b/packages/plugin-ext/src/main/browser/window-state-main.ts index 02701eef60614..36e7307f1f1aa 100644 --- a/packages/plugin-ext/src/main/browser/window-state-main.ts +++ b/packages/plugin-ext/src/main/browser/window-state-main.ts @@ -14,15 +14,22 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { WindowStateExt, MAIN_RPC_CONTEXT } from '../../common/plugin-api-rpc'; +import URI from 'vscode-uri'; +import { interfaces } from 'inversify'; +import { WindowStateExt, MAIN_RPC_CONTEXT, WindowMain } from '../../common/plugin-api-rpc'; import { RPCProtocol } from '../../common/rpc-protocol'; +import { UriComponents } from '../../common/uri-components'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; -export class WindowStateMain { +export class WindowStateMain implements WindowMain { - private proxy: WindowStateExt; + private readonly proxy: WindowStateExt; - constructor(rpc: RPCProtocol) { + private readonly windowService: WindowService; + + constructor(rpc: RPCProtocol, container: interfaces.Container) { this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.WINDOW_STATE_EXT); + this.windowService = container.get(WindowService); window.addEventListener('focus', () => this.onFocusChanged(true)); window.addEventListener('blur', () => this.onFocusChanged(false)); @@ -32,4 +39,15 @@ export class WindowStateMain { this.proxy.$onWindowStateChanged(focused); } + async $openUri(uriComponent: UriComponents): Promise { + const uri = URI.revive(uriComponent); + const url = encodeURI(uri.toString(true)); + try { + this.windowService.openNewWindow(url, { external: true }); + return true; + } catch (e) { + return false; + } + } + } diff --git a/packages/plugin-ext/src/plugin/plugin-context.ts b/packages/plugin-ext/src/plugin/plugin-context.ts index c5ef60a8e15d1..39832fb99e0d1 100644 --- a/packages/plugin-ext/src/plugin/plugin-context.ts +++ b/packages/plugin-ext/src/plugin/plugin-context.ts @@ -153,7 +153,7 @@ export function createAPIFactory( const commandRegistry = rpc.set(MAIN_RPC_CONTEXT.COMMAND_REGISTRY_EXT, new CommandRegistryImpl(rpc)); const quickOpenExt = rpc.set(MAIN_RPC_CONTEXT.QUICK_OPEN_EXT, new QuickOpenExtImpl(rpc)); const dialogsExt = new DialogsExtImpl(rpc); - const windowStateExt = rpc.set(MAIN_RPC_CONTEXT.WINDOW_STATE_EXT, new WindowStateExtImpl()); + const windowStateExt = rpc.set(MAIN_RPC_CONTEXT.WINDOW_STATE_EXT, new WindowStateExtImpl(rpc)); const notificationExt = rpc.set(MAIN_RPC_CONTEXT.NOTIFICATION_EXT, new NotificationExtImpl(rpc)); const editors = rpc.set(MAIN_RPC_CONTEXT.TEXT_EDITORS_EXT, new TextEditorsExtImpl(rpc, editorsAndDocumentsExt)); const documents = rpc.set(MAIN_RPC_CONTEXT.DOCUMENTS_EXT, new DocumentsExtImpl(rpc, editorsAndDocumentsExt)); @@ -501,8 +501,10 @@ export function createAPIFactory( }, getClientOperatingSystem(): PromiseLike { return envExt.getClientOperatingSystem(); + }, + openExternal(uri: theia.Uri): PromiseLike { + return windowStateExt.openUri(uri); } - }); const languageServer: typeof theia.languageServer = { diff --git a/packages/plugin-ext/src/plugin/window-state.ts b/packages/plugin-ext/src/plugin/window-state.ts index 3578377754926..a75a34cb3bca5 100644 --- a/packages/plugin-ext/src/plugin/window-state.ts +++ b/packages/plugin-ext/src/plugin/window-state.ts @@ -14,9 +14,11 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ +import URI from 'vscode-uri'; import { WindowState } from '@theia/plugin'; -import { WindowStateExt } from '../common/plugin-api-rpc'; +import { WindowStateExt, WindowMain, PLUGIN_RPC_CONTEXT } from '../common/plugin-api-rpc'; import { Event, Emitter } from '@theia/core/lib/common/event'; +import { RPCProtocol } from '../common/rpc-protocol'; export class WindowStateExtImpl implements WindowStateExt { @@ -25,7 +27,10 @@ export class WindowStateExtImpl implements WindowStateExt { private windowStateChangedEmitter = new Emitter(); public readonly onDidChangeWindowState: Event = this.windowStateChangedEmitter.event; - constructor() { + private readonly proxy: WindowMain; + + constructor(rpc: RPCProtocol) { + this.proxy = rpc.getProxy(PLUGIN_RPC_CONTEXT.WINDOW_MAIN); this.windowStateCached = { focused: true }; // supposed tab is active on start } @@ -43,4 +48,8 @@ export class WindowStateExtImpl implements WindowStateExt { this.windowStateChangedEmitter.fire(state); } + openUri(uri: URI): Promise { + return this.proxy.$openUri(uri); + } + } diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index 559efd0570986..9d562b5d25259 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -4744,6 +4744,18 @@ declare module '@theia/plugin' { */ export const sessionId: string; + /** + * Opens an *external* item, e.g. a http(s) or mailto-link, using the + * default application. + * + * *Note* that [`showTextDocument`](#window.showTextDocument) is the right + * way to open a text document inside the editor, not this function. + * + * @param target The uri that should be opened. + * @returns A promise indicating if open was successful. + */ + export function openExternal(target: Uri): PromiseLike; + } /**