From 796973487f7f6bf80a1e7c1d675bec026aa594b7 Mon Sep 17 00:00:00 2001 From: Dennis Huebner <dennis.huebner@gmail.com> Date: Mon, 22 Apr 2024 16:17:02 +0200 Subject: [PATCH] Add a new built-in handler to open files with system application #13535 (#13601) --- packages/core/src/electron-browser/preload.ts | 5 +- .../core/src/electron-common/electron-api.ts | 2 + .../src/electron-main/electron-api-main.ts | 7 ++- .../electron-navigator-menu-contribution.ts | 47 +++++++++++++++---- 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/packages/core/src/electron-browser/preload.ts b/packages/core/src/electron-browser/preload.ts index d7f6f30aa4ee0..b0903d1a764af 100644 --- a/packages/core/src/electron-browser/preload.ts +++ b/packages/core/src/electron-browser/preload.ts @@ -26,7 +26,7 @@ import { CHANNEL_IS_FULL_SCREEN, CHANNEL_SET_MENU_BAR_VISIBLE, CHANNEL_REQUEST_CLOSE, CHANNEL_SET_TITLE_STYLE, CHANNEL_RESTART, CHANNEL_REQUEST_RELOAD, CHANNEL_APP_STATE_CHANGED, CHANNEL_SHOW_ITEM_IN_FOLDER, CHANNEL_READ_CLIPBOARD, CHANNEL_WRITE_CLIPBOARD, CHANNEL_KEYBOARD_LAYOUT_CHANGED, CHANNEL_IPC_CONNECTION, InternalMenuDto, CHANNEL_REQUEST_SECONDARY_CLOSE, CHANNEL_SET_BACKGROUND_COLOR, - CHANNEL_WC_METADATA, CHANNEL_ABOUT_TO_CLOSE + CHANNEL_WC_METADATA, CHANNEL_ABOUT_TO_CLOSE, CHANNEL_OPEN_WITH_SYSTEM_APP } from '../electron-common/electron-api'; // eslint-disable-next-line import/no-extraneous-dependencies @@ -79,6 +79,9 @@ const api: TheiaCoreAPI = { showItemInFolder: fsPath => { ipcRenderer.send(CHANNEL_SHOW_ITEM_IN_FOLDER, fsPath); }, + openWithSystemApp: fsPath => { + ipcRenderer.send(CHANNEL_OPEN_WITH_SYSTEM_APP, fsPath); + }, attachSecurityToken: (endpoint: string) => ipcRenderer.invoke(CHANNEL_ATTACH_SECURITY_TOKEN, endpoint), popup: async function (menu: MenuDto[], x: number, y: number, onClosed: () => void, windowName?: string): Promise<number> { diff --git a/packages/core/src/electron-common/electron-api.ts b/packages/core/src/electron-common/electron-api.ts index 6abe167e8a784..6bcde6a4fb333 100644 --- a/packages/core/src/electron-common/electron-api.ts +++ b/packages/core/src/electron-common/electron-api.ts @@ -56,6 +56,7 @@ export interface TheiaCoreAPI { focusWindow(name?: string): void; showItemInFolder(fsPath: string): void; + openWithSystemApp(fsPath: string): void; getTitleBarStyleAtStartup(): Promise<string>; setTitleBarStyle(style: string): void; @@ -112,6 +113,7 @@ export const CHANNEL_FOCUS_WINDOW = 'FocusWindow'; export const CHANNEL_SHOW_OPEN = 'ShowOpenDialog'; export const CHANNEL_SHOW_SAVE = 'ShowSaveDialog'; export const CHANNEL_SHOW_ITEM_IN_FOLDER = 'ShowItemInFolder'; +export const CHANNEL_OPEN_WITH_SYSTEM_APP = 'OpenWithSystemApp'; export const CHANNEL_ATTACH_SECURITY_TOKEN = 'AttachSecurityToken'; export const CHANNEL_GET_TITLE_STYLE_AT_STARTUP = 'GetTitleStyleAtStartup'; diff --git a/packages/core/src/electron-main/electron-api-main.ts b/packages/core/src/electron-main/electron-api-main.ts index 485d917c9a288..d5966536dd470 100644 --- a/packages/core/src/electron-main/electron-api-main.ts +++ b/packages/core/src/electron-main/electron-api-main.ts @@ -53,7 +53,8 @@ import { CHANNEL_REQUEST_SECONDARY_CLOSE, CHANNEL_SET_BACKGROUND_COLOR, CHANNEL_WC_METADATA, - CHANNEL_ABOUT_TO_CLOSE + CHANNEL_ABOUT_TO_CLOSE, + CHANNEL_OPEN_WITH_SYSTEM_APP } from '../electron-common/electron-api'; import { ElectronMainApplication, ElectronMainApplicationContribution } from './electron-main-application'; import { Disposable, DisposableCollection, isOSX, MaybePromise } from '../common'; @@ -164,6 +165,10 @@ export class TheiaMainApi implements ElectronMainApplicationContribution { shell.showItemInFolder(fsPath); }); + ipcMain.on(CHANNEL_OPEN_WITH_SYSTEM_APP, (event, fsPath) => { + shell.openPath(fsPath); + }); + ipcMain.handle(CHANNEL_GET_TITLE_STYLE_AT_STARTUP, event => application.getTitleBarStyleAtStartup(event.sender)); ipcMain.on(CHANNEL_SET_TITLE_STYLE, (event, style) => application.setTitleBarStyle(event.sender, style)); diff --git a/packages/navigator/src/electron-browser/electron-navigator-menu-contribution.ts b/packages/navigator/src/electron-browser/electron-navigator-menu-contribution.ts index 6e12555784473..3020bd5f4c335 100644 --- a/packages/navigator/src/electron-browser/electron-navigator-menu-contribution.ts +++ b/packages/navigator/src/electron-browser/electron-navigator-menu-contribution.ts @@ -14,17 +14,19 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** -import { Command, CommandContribution, CommandRegistry, MenuContribution, MenuModelRegistry, SelectionService } from '@theia/core'; -import { CommonCommands, KeybindingContribution, KeybindingRegistry } from '@theia/core/lib/browser'; +import { Command, CommandContribution, CommandRegistry, MenuContribution, MenuModelRegistry, SelectionService, URI } from '@theia/core'; +import { CommonCommands, KeybindingContribution, KeybindingRegistry, OpenWithService } from '@theia/core/lib/browser'; import { WidgetManager } from '@theia/core/lib/browser/widget-manager'; +import { nls } from '@theia/core/lib/common'; +import { FileUri } from '@theia/core/lib/common/file-uri'; +import { isOSX, isWindows } from '@theia/core/lib/common/os'; +import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler'; +import '@theia/core/lib/electron-common/electron-api'; import { inject, injectable } from '@theia/core/shared/inversify'; import { FileStatNode } from '@theia/filesystem/lib/browser'; -import { FileNavigatorWidget, FILE_NAVIGATOR_ID } from '../browser'; -import { NavigatorContextMenu, SHELL_TABBAR_CONTEXT_REVEAL } from '../browser/navigator-contribution'; -import { isWindows, isOSX } from '@theia/core/lib/common/os'; import { WorkspaceService } from '@theia/workspace/lib/browser'; -import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler'; -import '@theia/core/lib/electron-common/electron-api'; +import { FILE_NAVIGATOR_ID, FileNavigatorWidget } from '../browser'; +import { NavigatorContextMenu, SHELL_TABBAR_CONTEXT_REVEAL } from '../browser/navigator-contribution'; export const OPEN_CONTAINING_FOLDER = Command.toDefaultLocalizedCommand({ id: 'revealFileInOS', @@ -34,6 +36,12 @@ export const OPEN_CONTAINING_FOLDER = Command.toDefaultLocalizedCommand({ /* linux */ 'Open Containing Folder' }); +export const OPEN_WITH_SYSTEM_APP = Command.toDefaultLocalizedCommand({ + id: 'openWithSystemApp', + category: CommonCommands.FILE_CATEGORY, + label: 'Open With System Editor' +}); + @injectable() export class ElectronNavigatorMenuContribution implements MenuContribution, CommandContribution, KeybindingContribution { @@ -46,14 +54,37 @@ export class ElectronNavigatorMenuContribution implements MenuContribution, Comm @inject(WorkspaceService) protected readonly workspaceService: WorkspaceService; + @inject(OpenWithService) + protected readonly openWithService: OpenWithService; + registerCommands(commands: CommandRegistry): void { commands.registerCommand(OPEN_CONTAINING_FOLDER, UriAwareCommandHandler.MonoSelect(this.selectionService, { execute: async uri => { - window.electronTheiaCore.showItemInFolder(uri['codeUri'].fsPath); + window.electronTheiaCore.showItemInFolder(FileUri.fsPath(uri)); }, isEnabled: uri => !!this.workspaceService.getWorkspaceRootUri(uri), isVisible: uri => !!this.workspaceService.getWorkspaceRootUri(uri), })); + commands.registerCommand(OPEN_WITH_SYSTEM_APP, UriAwareCommandHandler.MonoSelect(this.selectionService, { + execute: async uri => { + this.openWithSystemApplication(uri); + } + })); + this.openWithService.registerHandler({ + id: 'system-editor', + label: nls.localize('theia/navigator/systemEditor', 'System Editor'), + providerName: nls.localizeByDefault('Built-in'), + // Low priority to avoid conflicts with other open handlers. + canHandle: uri => (uri.scheme === 'file') ? 10 : 0, + open: uri => { + this.openWithSystemApplication(uri); + return {}; + } + }); + } + + protected openWithSystemApplication(uri: URI): void { + window.electronTheiaCore.openWithSystemApp(FileUri.fsPath(uri)); } registerMenus(menus: MenuModelRegistry): void {